Vue3入门
1、新特性: https://www.cnblogs.com/yaxinwang/p/13800734.html
- 数据响应重新实现(ES6的proxy代替ES5的Object.defineProperty)
- 源码使用ts重写,更好的类型推导
- 虚拟DOM新算法(更快,更小)
- 提供了composition api,为更好的逻辑复用与代码组织
- 自定义渲染器(app、小程序、游戏开发)
- Fragment,模板可以有多个根元素,不需要像Vue2一样必须定义一个根,如大div
使用Vue3下来最直观的感受就是,流程化编程,需要什么东西,我就拿什么方法。Vue2是将代码放进指定的方法内,如钩子等
2、关于Vue3的Proxy代理式响应
- Vue2的defineProperty只能监听某个属性,不能对全对象监听
- 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化
3、Vue2选项Api和Vue3组合Api
选项Api(Options):
- data选项写数据,methods选项写函数...,一个功能逻辑的代码分散。
- 优点:易于学习和使用,写代码的位置已经约定好
- 缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读。
- 补充:虽然提供mixins用来封装逻辑,但是出现数据函数覆盖的概率很大,不好维护
组合Api(Composition)
- 一个功能逻辑的代码组织在一起(包含数据,函数...)
- 优点:功能逻辑复杂繁多情况下,各个功能逻辑代码组织再一起,便于阅读和维护
- 缺点:需要有良好的代码组织能力和拆分逻辑能力
- 补充:为了能让大家较好的过渡到vue3.0的版本来,
也支持vue2.x选项API写法
3.1:组合Api的setup函数:是一个新的组件选项,作为组件中使用组合API的起点。从Vue2来看,他执行在beforeCreate之前,所以他里面的this为undefined,内部的函数与数据需要return后提供给模版
3.2:组合Api生命周期钩子:与Vue2有区别。Vue3中为了组合Api理清顺序,同样的钩子函数可以写多个,执行顺序与书写顺序相同
setup
创建实例前onBeforeMount
挂载DOM前onMounted
挂载DOM后onBeforeUpdate
更新组件前onUpdated
更新组件后onBeforeUnmount
卸载销毁前onUnmounted
卸载销毁后
3.2:reactive函数:定义一个复杂数据类型,成为响应式对象数据
3.3:ref函数:常用于简单数据类型定义为响应式数据。修改值,获取值的时候,需要.value。直接使用ref声明的响应式数据可以省略.value。当然也可以定义复杂数据,未知情况下用ref合适
3.4:toRef(s)函数:转换响应式对象中某个属性为单独响应式数据,并且值是关联的。若直接解构,值是普通的,不是响应式了。返回值是一个对象,属性在value内
setup () { // 1. 响应式数据对象 const obj = reactive({ name: 'ls', age: 10 }) // 2. 模板中只需要使用name数据 // 注意:从响应式数据对象中解构出的属性数据,不再是响应式数据 // let { name } = obj 不能直接解构,出来的是一个普通数据 const name = toRef(obj, 'name') const updateName = () => { // toRef转换响应式数据包装成对象,value存放值的位置 name.value = 'zs' } return {name, updateName}
当然,也可以把obj直接传给toRefs(注意s),将其所有属性转为响应式,再通过解构剥离对象。(响应式转解构后的响应式,只是在使用的时候可以省略obj.)
3.5:computed函数:当需要依赖现有的响应式数据,通过计算属性,返回一个新的响应式数据。计算属性不能修改。
计算属性内有set和get,一般使用get,即通过计算得到数据。但是也可以用set,给计算属性赋值,传值(如v-model的input传值)
const newAge = computed({ // get函数,获取计算属性的值 get(){ return age.value + 2 }, // set函数,当给计算属性设置值的时候触发 set (value) { age.value = value - 2 } })
3.6:watch函数:侦听器,监听数据变化。
//监听目标,操作,选项 watch(()=>obj.brand, (newValue,oldValue)=>{ console.log('brand数据改变了') },{ // 需要深度监听,如属性内还有对象 deep: true, // 默认触发 immediate: true })
如果要监听多个数据,则把要监听的对象打包成数组;如果要监听对象中某一个属性的变化,就要像上述一样,将数据写成返回该属性的方式才可以监听;监听某一属性变化的时候,如果有更深的对象需要监听,需要deep改成true
3.7:ref属性(需要ref函数区分,与Vue2的ref区分):获取DOM或者组件实例。单个元素直接ref,多个元素 :ref (冒号)
<!-- 单个元素 --> <div ref="dom">我是box</div> <!-- 被遍历的元素 --> <ul> <li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li> </ul> // 1. 获取单个元素 // 1.1 先定义一个空的响应式数据ref定义的 // 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。 const dom = ref(null) // 2. 获取v-for遍历的元素 // 2.1 定义一个空数组,接收所有的LI // 2.2 定义一个函数,往空数组push DOM const domList = []; const setDom = (el) => { domList.push(el); };return { dom, setDom };
这里存在一个边界问题,当组件更新的时候,DOM刷新会不断的赋值给旧dom,所以每次更新前,应该清空数组
// ref获取v-for遍历的DOM元素,需要在组件更新的时候重置接受dom元素的数组。 onBeforeUpdate(()=>{ list = [] })
3.8:父子通讯
3.8.1:父传子:父传一致,子传的时候,定义玩props,将props传入setup,因为Vue3的this指空。注意:在Vue3中v-model已经将.sync集成了
setup (props) { // 获取父组件数据money console.log(props.money) }
3.8.2:子传父:emit发射事件,不用this.$emit。emit要现在子组件的setup注册
setup(props,{emit}){ // emit 就是触发事件函数 }
3.8.3:依赖注入,和Vue2差不多,还是父组件provide,子组件inject
//父组件 // 将数据提供给后代组件 provide provide('money', money) // 将函数提供给后代组件 provide provide('changeMoney', changeMoney) //子、孙组件 // 接收祖先组件提供的数据 const money = inject('money') // 不能自己直接修改money数据,遵循单选数据流原则,在父内定义方法,将方法提供给子代,让其通知修改数据 const changeMoney = inject('changeMoney') const fn = () => { changeMoney(20) }
3.8.4:v-model的补充:在Vue2的时候,v-model传值,子若要修改父的,父还要接收一个方法来修改,为了方便,使用了.sync修饰符。Vue3中.sync修饰符整合进v-model内
<!-- <Son :modelValue="count" @update:modelValue="count=$event" /> --> <Son v-model="count" /> //直接代替
3.8.5:mixin:Vue2中就提供了mixin,可复用的逻辑放在mixin中可在任意组件复用,但是要考虑代码名称冲突的问题。Vue3中将函数封装出去,组合Api不存在这个问题,就不推荐使用mixin了