Vue3 学习笔记

官网:vuejs.org/

1. 项目搭建

使用 Vite 或 Vue CLI 来创建 Vue 3 项目。以 Vite 为例,在命令行执行以下命令:

perl 复制代码
npm init vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
npm run dev

2. 组合式 API

Vue 3 引入了组合式 API,它能让你更灵活地组织代码。

2.1 setup 函数

setup 函数是组合式 API 的入口,在组件创建之前执行。

xml 复制代码
<template>
  <div>{{ message }}</div>
</template>

<script setup>
import { ref } from 'vue';

const message = ref('Hello, Vue 3!');
</script>

2.2 refreactive

  • ref 用于创建响应式的基本类型数据。
  • reactive 用于创建响应式的对象或数组。
xml 复制代码
<template>
  <div>
    <p>{{ count }}</p>
    <p>{{ user.name }}</p>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';

const count = ref(0);
const user = reactive({ name: 'John' });
</script>

2.3 生命周期钩子

setup 函数中使用生命周期钩子,需要从 vue 导入相应的函数。

xml 复制代码
<template>
  <div></div>
</template>

<script setup>
import { onMounted } from 'vue';

onMounted(() => {
  console.log('Component is mounted');
});
</script>

生命周期阶段与函数

  1. 创建阶段
  • beforeCreate

    • 这是实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。此时,datamethods 等属性都还未初始化,不能访问它们。
    • 示例代码:
javascript 复制代码
new Vue({
  beforeCreate() {
    console.log('实例初始化,data 和 methods 未初始化');
  }
});
  • created

    • 实例已经创建完成之后被调用。在这一步,实例已经完成了数据观测 (data observer)、propertymethod 的计算、watch/event 事件回调的配置等。然而,挂载阶段还没有开始,$el 属性目前不可用。
    • 示例代码:
javascript 复制代码
new Vue({
  data() {
    return {
      message: 'Hello Vue!'
    };
  },
  created() {
    console.log(this.message); // 可以访问 data 中的属性
  }
});
  1. 挂载阶段
  • beforeMount

    • 在挂载开始之前被调用:相关的 render 函数首次被调用。此时模板已经编译完成,但还未挂载到页面上,$el 还是虚拟 DOM。
    • 示例代码:
javascript 复制代码
new Vue({
  template: '<div>{{ message }}</div>',
  data() {
    return {
      message: 'Hello Vue!'
    };
  },
  beforeMount() {
    console.log('模板编译完成,但未挂载到页面');
  }
});
  • mounted

    • el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。此时,Vue 实例已经将模板渲染到页面上,可以进行 DOM 操作。
    • 示例代码:
javascript 复制代码
new Vue({
  template: '<div id="app">{{ message }}</div>',
  data() {
    return {
      message: 'Hello Vue!'
    };
  },
  mounted() {
    console.log(this.$el.textContent); // 可以访问渲染后的 DOM 内容
  }
}).$mount('#app');
  1. 更新阶段
  • beforeUpdate

    • 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在数据更新前访问现有的 DOM,比如手动移除已添加的事件监听器。
    • 示例代码:
javascript 复制代码
new Vue({
  data() {
    return {
      count: 0
    };
  },
  beforeUpdate() {
    console.log('数据即将更新,DOM 还未更新');
  }
});
  • updated

    • 由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。调用时,组件 DOM 已经更新,所以可以执行依赖于 DOM 的操作。不过要注意避免在此期间更改数据,否则可能导致无限循环更新。
    • 示例代码:
javascript 复制代码
new Vue({
  data() {
    return {
      count: 0
    };
  },
  updated() {
    console.log('数据更新完成,DOM 已更新');
  }
});
  1. 销毁阶段
  • beforeDestroy

    • 实例销毁之前调用。在这一步,实例仍然完全可用,datamethodswatchevent 等都还可以正常使用。通常用于解绑自定义事件、清除定时器等操作。
    • 示例代码:
javascript 复制代码
new Vue({
  data() {
    return {
      timer: null
    };
  },
  created() {
    this.timer = setInterval(() => {
      console.log('定时器运行中');
    }, 1000);
  },
  beforeDestroy() {
    clearInterval(this.timer); // 清除定时器
    console.log('实例即将销毁');
  }
});
  • destroyed

    • 实例已经完全销毁之后调用。所有的事件监听器和子实例也已经被销毁。此时实例已经无法再使用。
    • 示例代码:
javascript 复制代码
new Vue({
  destroyed() {
    console.log('实例已销毁');
  }
});

3. 组件通信

3.1 父传子

父组件通过属性向子组件传递数据。

xml 复制代码
<!-- 父组件 -->
<script setup>
import Header from './components/header.vue'
</script>

<template>
  <Header propsName="tom"/>
</template>

<style scoped>
</style>

<!-- 子组件 -->
<script setup>
    const props = defineProps(["propsName"]);
    console.log(props);
</script>

<template>
<h2>Header</h2>
</template>

<style scoped>
</style>

3.2 子传父

子组件通过触发自定义事件向父组件传递数据。

xml 复制代码
<!-- 子组件 -->
<script setup>
    //子组件向父组件传递数据,使用宏函数
    //参数是数组,数组里的元素是会触发自定义事件的名称
    const emits = defineEmits(["getStudent"])
    emits("getStudent", {name:"mary", age:10});
</script>

<template>
<h2>Header</h2>
</template>

<style scoped>
</style>

<!-- 父组件 -->
<script setup>
import Header from './components/header.vue'
import Footer from './components/footer.vue'
import {reactive} from "vue";

//响应式数据
const student = reactive({
  name: 'tom',
  age: 18
})

const emitGetStudent = (name, age) => {
 student.name = name
  student.age = age
}
</script>

<template>
  <Header @getStudent="emitGetStudent"/>
  {{student.name}}-{{student.age}}
</template>

<style scoped>
</style>

4. 路由管理

使用 vue-router 进行路由管理。

4.1 安装

css 复制代码
npm install vue-router@4

4.2 配置路由

javascript 复制代码
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

4.3 在主应用中使用路由

javascript 复制代码
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

const app = createApp(App);
app.use(router);
app.mount('#app');

5. 状态管理

使用 Pinia 进行状态管理。

5.1 安装

复制代码
npm install pinia

5.2 创建 store

javascript 复制代码
// stores/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++;
    }
  }
});

5.3 在组件中使用 store

xml 复制代码
<template>
  <div>
    <p>{{ counterStore.count }}</p>
    <button @click="counterStore.increment">Increment</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '../stores/counter';

const counterStore = useCounterStore();
</script>

前后端通信

Axios是基于Promise的网络请求库,它可以发送http请求并接收服务器返回的响应数据

Axios返回的是一个Promise对象

javascript 复制代码
//post请求 post
let data = { //参数
    name: 'tom',
    web: 'baidu.com'
};

axios.post('http://127.0.0.1/post', data, {
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
}).then(response => {
    console.log("post.data:", response.data)
}).catch(error => {
    console.log("post.error:", error)
}).finally(() => {
    console.log("post.finally")
});

同步与异步

  • 同步

    • 执行特点:代码按编写顺序逐行执行,后续代码需等待当前代码完成才能执行。遇到耗时操作(如网络请求)时,主线程会被阻塞,直到操作结束。
    • 举例理解:像单车道发生交通事故致堵塞,只有拖走事故车,后续车辆才能通行。
  • 异步

    • 执行特点:遇到耗时操作,主线程不阻塞,会继续执行后续代码,无需等待耗时操作完成。

    • 举例理解:多车道高速路发生事故,可走其他车道继续行驶。

async 和 await

  • async

    • 函数特性 :标记为async的函数会返回一个Promise对象 。比如:
javascript 复制代码
async function asyncFunction() {
    return '这是async函数的返回值';
}
// 调用async函数,会得到一个Promise对象
asyncFunction().then(result => {
    console.log(result); 
}); 
  • await

    • 使用规则 :只能在async函数内部使用。当执行到await关键字时,会暂停函数后续执行,等待await后面的Promise对象(常为异步操作,如网络请求)完成,然后获取其返回数据继续执行。例如:
javascript 复制代码
async function getData() {
    // 模拟异步操作,返回Promise对象
    const promise = new Promise((resolve) => {
        setTimeout(() => {
            resolve('异步操作结果');
        }, 1000);
    });
    // await等待Promise完成并获取结果
    const result = await promise; 
    console.log(result); 
}
getData(); 

结合网络请求场景(假设使用axios库发起请求):

javascript 复制代码
const axios = require('axios');
async function getRemoteData() {
    try {
        const response = await axios.get('https://api.example.com/data');
        console.log(response.data);
    } catch (error) {
        console.error(error);
    }
}
getRemoteData();

上述代码中,await等待axios的网络请求完成,获取响应数据后继续后续操作,若请求出错则进入catch捕获错误。

6. 指令

6.1 内置指令

  • v-bind:缩写是:,用于把数据绑定到 HTML 元素的属性上。
  • v-on:缩写是 @它用于监听 DOM 事件,使用缩写同样能使代码变得更简洁。
  • v-model:表单数据的双向绑定操作,让开发者能更便捷地处理用户输入。
  • v-ifv-elsev-else-if:用于条件渲染。
  • v-for:用于列表渲染。
xml 复制代码
<template>
  <div>
    <img :src="imageUrl" alt="Example" />
    <button @click="handleClick">Click me</button>
    <p v-if="showMessage">This message is visible</p>
    <ul>
      <li v-for="item in items" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const imageUrl = ref('https://example.com/image.jpg');
const showMessage = ref(true);
const items = ref([
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' }
]);

const handleClick = () => {
  console.log('Button clicked');
};
</script>

6.2 自定义指令

xml 复制代码
<template>
  <div v-focus>Input will be focused on mount</div>
</template>

<script setup>
import { defineDirective } from 'vue';

const vFocus = defineDirective({
  mounted(el) {
    el.focus();
  }
});
</script>

7. 插件

可以创建和使用插件来扩展 Vue 应用的功能。

javascript 复制代码
// plugins/myPlugin.js
const myPlugin = {
  install(app, options) {
    app.config.globalProperties.$myMethod = () => {
      console.log('This is a global method');
    };
  }
};

export default myPlugin;
javascript 复制代码
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import myPlugin from './plugins/myPlugin';

const app = createApp(App);
app.use(myPlugin);
app.mount('#app');
xml 复制代码
<template>
  <div></div>
</template>

<script setup>
const { proxy } = getCurrentInstance();
proxy.$myMethod();
</script>
相关推荐
电商api接口开发1 分钟前
ASP.NET MVC 入门指南二
前端·c#·html·mvc
亭台烟雨中14 分钟前
【前端记事】关于electron的入门使用
前端·javascript·electron
泯泷28 分钟前
「译」解析 JavaScript 中的循环依赖
前端·javascript·架构
抹茶san31 分钟前
前端实战:从 0 开始搭建 pnpm 单一仓库(1)
前端·架构
Senar1 小时前
Web端选择本地文件的几种方式
前端·javascript·html
烛阴1 小时前
UV Coordinates & Uniforms -- OpenGL UV坐标和Uniform变量
前端·webgl
姑苏洛言1 小时前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
烛阴2 小时前
JavaScript 的 8 大“阴间陷阱”,你绝对踩过!99% 程序员崩溃瞬间
前端·javascript·面试