文章目录
1 为什么学vue3 ?
目标 了解vue3 现状,以及他的优点,展望他的未来
vue3现状:
- vue-next 2020年09月18日,正式发布vue3.0 版本,但是由于刚发布周边生态不支持,大多数开发者人处于观望
- 现在主流组件库都已经发布了支持vue3.0的版本,其他生态也在不断的完善中,这是趋势
- element-plus: 基于vue3.0 的桌面端组件库
- vant: vant3.0 版本 有赞前端团队 开源移动端组件库
- ant-design-vue: Ant Design Vue2.0 版本,社区根据蚂蚁 antdesign 开发
vue3优点:
- 最火框架,他是国内最火的前端框架之一,官方文档为中文文档
- 性能提升,运行速度是vue2.x 的 1.5倍
- 体积更小,按需编译 体积比vue2.x 要更小
- 类型推断,更好的支持ts 这也是一个趋势
- 高级给予,暴露了更底层的API和提供更先进的内置组件
- 组合API,能够更好的组织逻辑,封装逻辑,复用逻辑
vue3展望:
- 这是趋势,越来越多的企业将来肯定会升级到vue3.0
- 大型项目,由于对ts的友好 越来越多大型项目可以用vue3.0
总结 为什么要学习vue3?
- 使用市场学习流行的技术 提高自己的竞争力,给自己加薪
2 vite 基本使用
目标:了解vite是什么,使用vite创建vue项目,用来学习vue3
vite是什么?
-
他是一个更加轻量(热更新速度块,打包构建速度快)的vue项目脚手架工具
-
它相对于vue-cli它默认安装的插件非常少 随着开发过程以来增多,需要自己额外配置
-
所以:在单纯学习vue3语法会使用它,后面做项目可以继续使
用vue-cli
vite 基本使用:
- 创建项目 npm init vite-app 项目名称 或者 yarn create vite-app 项目名称
- 安装依赖 npm i 或者 yarn
- 启动项目 npm run dev 或者 yarn dev
总结:vite 是什么?
-
下一代前端开发与构建工具
-
使用vite创建项目 学习vue3 语法 使用vue-cli 创建项目正式开发
3 创建vue 项目
目标:掌握如何创建vue3 应用实例
基本步骤:
- 在main.js 导入createApp 函数
- 定义App.vue 组件 导入main.js
- 使用createApp函数基于App.vue组件创建应用实例
- 挂在之index.html 的app容器
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
总结:如何创建vue应用实例?
通过createApp创建应用实例 -> 拓展功能将来都是在app上进行
4 选项API和组合API
目标:理解什么是选项API写法 什么是组合API写法
vue2.x 中的选项API 是在各个选项中实现一个共同逻辑,代码是分散的,项目过大时,不好维护,无论是阅读性还是可维护性都比较差
vue3.x 中组合式API 的每个逻辑是集中在一起的,便于后期的维护,书写起来,也不用对照前后的代码,去书写一个功能,阅读性,可维护性更高
什么是选项API写法:Option API
-
咱们再vue2.x 项目中使用的就是选项API 写法
- 代码风格:data选项书写数据 methods 选项写方法 一个功能逻辑的代码比较分散
-
优点:易于学习和使用 写代码的位置已经约定好
-
缺点:代码组织性比较差,相似的逻辑代码不便于复用,逻辑复杂代码多了就不好阅读
-
补充:虽然提供mixins用来封装逻辑,但是出现数据函数覆盖的概率比较大,不好维护,容易出现bug,变量的隐式声明。
什么是组合API写法:Componsition API
-
vue3.x 项目中 将会使用组合API 写法
- 代码风格:一个功能逻辑的代码组织在一起(包含数据,函数)
-
优点:功能逻辑复杂繁多的情况下,各个功能逻辑代码组织在一起,便于阅读和维护
-
缺点:需要有良好的代码组织能力和拆分逻辑的能力
-
补充:为了能让大家更好的过度到vue 3.0 ,也会支持选项API
5 组合API-setup 函数
目标:掌握setup函数的基本使用
使用细节:
- setup 是一个新的组件选项 作为组件中使用组合API的起点
- 从组件的生命周期来看 他的执行再组件实例创建之前 vue2.x beforeCreate 执行
- 这就意味着在setup 函数中 this 还不是组件实例 this此时是undefined
- 在模板中需要使用的数据和函数 需要在setup返回出去
6 组合API-生命周期
vue2 生命周期钩子 | vue3生命周期钩子 | |
---|---|---|
beforeCreate | setup | |
创建实例 | created | |
beforeMount | onBeforeMount | |
挂载DOM | mounted | onMounted |
beforeUpdate | onBeforeUpdate | |
组件更新 | updated | onUpdated |
beforeDestroy | onbeforeUnmount | |
组件销毁 | destroyed | onUnmounted |
在vue2.x 中 钩子函数选项只可以写一个
在vue3.0 中 钩子函数可以定义多个 用于实现不同的逻辑
7 组合API reactive 函数
目标:掌握使用reactive函数定义响应式数据
定义响应式数据:
reactive 是什么?
他是一个函数
有什么用?
它可以定义一个复杂数据类型 成为响应式数据
怎么用?
const obj = reactive({
name: "小王",
age: 18,
});
为什么要用?
因为vue3.0 生命的普通变量并不是响应式的
使用场景?
当需要定义一些复杂的响应式数据的时候 需要用reactive 进行转换
优缺点?
8 组合API toRef函数
目标:掌握使用toRef函数转换响应式对象中某个属性为单独响应式数据, 并且值是关联的。
toRef 是什么?
他是一个函数
有什么用?
它可以转换 响应式对象 中 某个 属性为单独响应式数据,并且 值是关联的
怎么用?
// 定义响应式对象
let obj = reactive({
name: "张三",
age: 18,
});
let name = toRef(obj, "name");
// 抽离响应式数据 (抽离不代表解除关联)
// 这个时候可以将对象的某个属性 转为 一个响应式对象 注意是对象
let name = toRef(obj, "name");
// 修改数据 value是存放值的地方
name.value = 5555;
为什么要用?
当我们定义了一个响应式对象 ,我们恰好在页面中只想使用它的一个属性,这个时候我们通过解构赋值,得到的属性并不是响应式的,如果想要该属性为响应式,需要我们通过toRef转换为响应式的,并且关联原有的数据。
注意:这个时候直接通过ref转为响应式数据也是可以的,但是会失去与原有数据的关联性,他将是一个全新的响应式数据,与原有对象无关!
使用场景?
有一个响应式对象数据,但是模板中 只需要使用其中一项数据
注意:从响应式数据对象中结构的数据,不再是响应式数据了
9 组合API toRefs 函数
目标:掌握使用toRefs函数定义转换响应式中所有属性为响应式数据 通常用于结构 | 展开reactive定义的对象
toRefs 是什么?
他是一个函数
有什么用?
它可以 转换 响应式对象 中所有属性为单独响应式数据 对象成为普通对象
怎么用?
// 定义响应式数据
let obj1 = reactive({
name1: "reactive name",
age1: 18,
});
// 调用refs 函数 将对象的每一项都转为响应式数据
// 此时 obj1 和 obj3 是有关联的
let obj3 = toRefs(obj1); // 接受的参数为reactive对象
// 修改的时候需要注意
// 可以直接修改 obj1
obj.name1 = '修改啦'
// 也可以修改包装之后处理的对象 但是 因为是响应式对象 他的值存在value中
obj3.name1.value = "修改啦";
// 导出
return{
// 记得导出转换之后的对象
...obj3
// 模板中可以直接使用属性 而不用通过对象. 的方式进行调用
}
// 注意 如果 toRefs 接受的是一个普通对象
// 也可以将这个对象的所有属性转为响应式的 不过 此时原有数据并不是响应式的,通过toRefs 处理之后的数据是响应式的
为什么要用?
使用场景?
剥离响应式对象 想使用响应式对象中的多个或者所有属性作为响应式数据
10 组合API ref函数
目标:掌握使用ref函数定义响应式数据,一般用于简单类型数据
ref 是什么?
他是一个函数
有什么用?
通常用于 简单数据类型定义为响应式数据
怎么用?
//ref() 通常接受一个普通数据类型
// 返回值为一个响应式数据
//修改的时候 :
//一定要通过 .value 对响应式数据进行修改
//在模板中是用ref申明的响应式数据 可以省略.value
const num = ref(5)
num.value = 10
// ref 也可以接受一个 复杂数据类型 其内部会调用reactive函数
const ref = ref({
name:"666"
})
// 当对未来要定义的响应式数据 类型是未知的
const data = ref(null)
为什么要用?
原生vue 不支持响应式数据 我们如果需要使用响应式数据 必须对原有数据进行转化
使用场景?
// 1.当你明确知道 需要的一个响应式数据是 对象 那么就是用reactive即可
// 2.其他情况下使用ref
11 组合API computed函数
目标:掌握使用computed 函数定义计算属性
什么是computed?
计算属性是用来计算数据的函数
有啥用呢 ?
computed 是用来定义计算属性的 计算属性不可以修改
是一个函数 在vue2.x 是一个选项
怎么用呢?
// 用法1 - 普通用法 传函数
const age = ref(18);
const newAge = computed(() => {
// 该函数的返回值 就是计算属性的值
return age.value + 2;
});
return {
age,
newAge,
};
注意:
1. vue3计算属性是可以多次调用的
2. 计算属性接收一个回调函数 return的值 就是计算属性的值
3. 计算属性是可以进行缓存的 当依赖的响应式数据未发生改变的时候 ,计算属性会返回上次计算的结果.
4. 计算属性默认是只读的,要想实现双向数据绑定,可以传一个对象进去
// 用法2 - 高级用法 传对象
const newAge = computed({
// get 函数 获取计算属性的值
get() {
return age.value + 2;
},
// set 函数 当你给计算属性设置值的时候触发 监听计算属性值得改变
set(value) {
age.value = value - 2;
},
});
// 这样就实现了双向数据绑定的用法
使用场景?
1. 当你需要以来一个现有的响应式数据,根据一定逻辑得到一个新的数据
优缺点?
12 组合API watch函数
目标:掌握使用watch函数定义侦听器
定义计算属性:
watch 函数,用来定义侦听器的
// vue3 监听复杂数据类型 对象的时候 默认开启深度监听
// 但是 任然无法监听到oldvalue
监听ref 定义的响应式数据
const count = ref(0);
const add = () => {
count.value++;
};
// 当需要监听数据的变化 需要使用ref
// 1. 监听一个ref数据
// 1.1 第一个参数 需要监听的目标
// 1.2 第二个参数 改变后的回调函数
watch(count, (newVal, oldVal) => {
console.log(newVal, oldVal);
});
监听多个响应式数据变化
// 监听多个响应式数据 数组形式
watch([count, obj], () => {
console.log("count或者obj改变啦");
});
监听reactive定义的响应式数据
// 直接监听
const obj = reactive({
name: "la",
age: 18,
info: {
msg: "lalal 我是里层的对象",
},
});
const mdName = () => {
obj.name = 888;
};
const mdMsg = () => {
obj.info.msg = 888;
};
watch(obj, (newVal, oldVal) => {
console.log("obj数据改变了~");
});
监听reactive定义的响应式数据 某一个属性 默认开启深度监听
// 监听 reactive 中的某个属性,要用回调函数返回值形式
watch(
() => obj.name,
() => {
console.log("监听obj.name 的变化");
}
);
深度监听 监听reactive 定义的响应式对象的对象属性
要监听对象的某个属性的时候 如果该属性不是对象的话,是默认开启深度监听的
如果需要坚挺的这个属性又是一个对象的时候 这个时候 是无法监听到 这个对象属性的 需要开启深度监听
const obj = reactive({
name: "la",
age: 18,
info: {
msg: "lalal 我是里层的对象",
},
});
watch(
() => obj.info,
() => {
console.log("obj.info.msg 改变啦");
},
{
deep: true,
}
);
13 组合API ref属性
目标 :掌握使用ref属性绑定DOM或组件
获取DOM 或组件实例 可以使用ref属性 写法与vue2.0需区分开
获取单个DOM 或 组件
// 1. 定义以一个空的响应式数据 ref定义的
// 2. setup 中返回该数据 想获取那个DOM 在该元素上使用ref属性绑定该数据即可
const box = ref(null);
console.log(box);
return {
box,
};
<template>
<div ref="box">我是box</div>
</template>
获取v-for 遍历的DOM 或组件
// 2 获取v-for 遍历的元素
// 2.1 定义一个空数组 接收所有的li
// 2.2 定义一个函数 往空数组中pushDOM
const list = [];
const setDom = (el) => {
console.log("setDOM");
list.push(el);
console.log(list);
};
<template>
<ul>
<li v-for="i in 4" :key="i" :ref="setDom">{{ i }}</li>
</ul>
</template>
总结:
- 单个元素 :先申明ref响应式数据 返回给模板 通过ref绑定数据
- 遍历的元素:先定义一个空数组(非响应式)定义一个函数获取元素 返回给模板使用 通过ref绑定这个
14 组合API 父子通讯
目标:掌握使用props 选项和emits选项完成父子通讯
父传子
// 父组件
<template>
<Son :count="count"></Son>
</template>
setup() {
const count = ref(0);
return {
count,
};
},
// 子组件
// 和vue2.x 一样 正常接收数据
props: {
count: {
type: Number,
default: 0,
},
},
// 如果想要在setup函数中使用数据 可以直接传参 props
setup(props) {
console.log(props);
},
子传父
// 子组件
<template>
<h3>我是子组件</h3>
<p>{{ count }}</p>
<button @click="changeMoney">买快乐~ -50</button>
</template>
// 第一个参数为props 第二个参数为context
// context 中有emit方法
setup(props, context) {
// 获取父组件传来的值
console.log(props);
// 向父组件传值
const changeMoney = () => {
// 消费50 元
// 通知父组件 money需要变成50
context.emit("change-money", 50);
};
return {
changeMoney,
};
},
// 父组件
<div class="container">
<h1>我是父组件里</h1>
<p>{{ count }}</p>
<hr />
<Son :count="count" @change-money="updateMoney"></Son>
</div>
setup() {
const count = ref(100);
const updateMoney = (money) => {
count.value -= 50;
};
return {
count,
updateMoney,
};
},
拓展:
-
在vue2.x 的时候 .sync 除去v-model的情况下实现双向数据绑定的另外一种方式
<Son :money='money' @update:money="fn"><Son>
简写:
<Son :money.sync='money'><Son>
-
在vue 3.0 的时候 使用v-model:money=“money” 即可
// 父组件 <Son v-model:count="count"></Son> // 子组件 const changeMoney = () => { // 消费50 元 // 通知父组件 money需要变成50 context.emit("update:count", 50); };
总结:
-
父传子:在setup 中使用props 数据,接受的第一个参数就是
-
子传父:触发自定义时间的时候 emit 来自setup的第二个参数 context对象
-
在vue2.x 中 v-model 和 .sync 已经和并成 v-model 指令
15 组合API 依赖注入
目标:掌握使用provide函数和inject函数完成后代组件通讯
使用场景: 有一个父组件 有很多后代组件 都需要共享父组件的数据
//父组件
setup() {
const money = ref(1000);
const changeMoney = (val) => {
console.log("changeMoney");
money.value -= 50;
};
// 将数据提供给后代组件 provide
provide("money", money);
// 将修改数据的函数给后代组件
provide("changeMoney", changeMoney);
return {
money,
};
},
// 后代组件接收数据
setup() {
const money = inject("money");
const changeMoney = inject("changeMoney");
// 孙组件 消费50 通知父组件App 进行修改
// 不能自己修改数据 遵循单项数据流 在哪定义在那修改
const fn = () => {
changeMoney(50);
};
return {
money,
fn,
};
},
总结:
- provide 函数提供数据和修改数据的函数给后代组件(单项数据流)
- inject函数给当前组件注入provide 提供的数据和函数
16 v-model 语法糖
目标 掌握vue3 的 v-model 的语法糖原理
在 vue 2.0 中 v-model 语法糖 简写
<Son :value="msg" @input='msg=$event'/>
在vue 3 中v-model 语法糖有所调整
<Son :modelValue="msg" @update:modelValue="msg=$event"/>
//父组件
<!-- <Son :modelValue="count" @update:modelValue="count = $event"> </Son>-->
<!-- 简写-->
<Son v-model="count"></Son>
// 子组件
setup(props, { emit }) {
const fn = () => {
console.log("fn");
// 改变数据
emit("update:modelValue", 100);
};
return { fn };
},
17-mixins 语法
目标: 掌握mixins 语法的基本使用 Vue2.x 封装逻辑的方式 Vue3.0 建议使用组合式API
官方解释:
- 混入(mixins)提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入时,所有混入对象的选项将被"混合"进入组件本身的选项
理解全局混入:所有组件混入了这些逻辑代码
// vue 2
Vue.mixin({ 选项 })
// vue 3
app.mixin({
选项
})
总结:在vue2.0 中一些可复用逻辑可以用mixins来封装,但是需要考虑逻辑代码冲突的问题。 vue3.0 的组合API很好的解决了这个问题 ,就不再推荐使用mixins了