Vue3快速入门
Vue3.0 简介
- 2020年9月18日,Vue.js 发布3.0版本,代号:One Piece(海贼王)
Vue3 带来了什么
- 性能的提升,源码的升级,拥抱TypeScript,新的特性 Composition API。
新的特性
Composition API(组合API)
- setup 设置
- ref 与 reactive
- watch 与 watchEffect
- provide 与 inject
新的内置组件
- Fragment
- Teleport
- Suspense
其他改变
-
新的生命周期钩子
-
data选项应始终生命为一个函数
-
移除keyCode支持为v-on的修饰符
-
DOM节点的挂载方式
-
DOM节点挂在的方式从Vue2.0中 new Vue() 实例的方式变成了Vue3中createApp()方法。
-
//Vue2 new Vue({ el: '#app', router, store, render: h => h(App) }) //Vue3 createApp(App).$mount("#app");
-
Composition API(组合API)
官方文档:介绍 | Vue.js
- 使用Vue2的Option API写组件,随着业务复杂度越来越高,代码量会不断的加大;
- 由于相关业务的代码要遵循option的配置写到特定的区域,导致后续维护非常的复杂,同时可复用性不高,而Composition API就是为了解决这个问题而生的。
拉开序幕的 setup
-
理解:Vue3.0中一个新的配置项,值为一个函数。
-
setup 是所有 Composition API(组合API)"表演的舞台",(入口函数)。
-
组件中所用到的:数据,方法等等,均要配置在setup中。
-
setup 函数的两种返回值:
- 若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用。
- 若返回一个渲染函数:则可以自定义渲染内容。(了解)
-
尽量不要与 Vue2.x 配置混用
-
Vue2.x配置(data,methods,computed。。。)中可以访问到setup中的属性,和方法。
但在 setup中不能访问到Vue2.x配置(data,methods,computed。。。),因为setup执行时期的问题:setup会在 beforeCreate执行,所以this是undefined,无法获取 Vue2中配置的数据与方法。。。。反而言之,setup函数执行完毕会返回一个对象对象 对象中的属性和方法都会挂载到vue实例上,所以在Vue2.0中可以访问到setup中的数据。如果有重名,setup优先
-
-
setup的执行时机
- setup在组件实例创建之前便开始执行,因此在setup选项中没有this。这也意味着,除了props,你将无法访问到组件任何的状态或者方法。 以前data里面的数据我们是直接可以绑定到template上面的,而在vue3.0 Composition API中需要在setup里面return出去,那么数据便会被合并到渲染的上下文中去,从而在template中使用。(在beforeCreate之前执行,this是undefined)
-
setup 的参数
-
setup(props,context)/setup(props,{attrs,slots,emit})
- props:值为对象,包含组件外部传递过来,且组件内部声明接受了的属性。
- context:上下文对象
- attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于 this.$attrs
- slots:收到的插槽内容,相当于 this.$slots
- emit:分发自定义事件的函数,相当于 this.$emitu1kh
-
参数 含义 props 包含props配置声明且传入了的所有属性的对象(props对象是响应式的,不要去解构,解构会失去响式性) attrs 包含没有在props配置中声明的属性的对象,相当于this.$attrs slots 包含所有传入的插槽内容的对象,相当于this.$slots emit 用来分发自定义事件的函数,相当于this.$emit
-
ref 函数
- 作用:定义一个响应式的数据。
- 语法:const xxx = ref(initValue);
- 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
- js中操作数据:xxx.value
- 模板中读取数据,不需要.value 直接使用数据
- 备注
- 接受的数据可以是:基本类型,也可以是对象类型。
- 基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成。
- 对象类型的数据:内部“求助“了Vue3.0中的一个函数 ------- reactive 函数 底层是用Proxy来进行拦截。
reactive 函数
- 作用:定义一个对象类型的响应式数据(基本类型不要用他,要用ref)
- 语法:const 代理对象 = reactive(目标对象),返回一个代理对象(Proxy的实例对象,简称proxy对象)
- reactive 定义的响应式数据是 ”深层次的“
- 内部基于 ES6 的 Proxy实现,通过代理对象操作源对象内部数据进行操作。
Vue3.0 与 2.x 的响应式原理
-
Vue2.x的响应式
-
实现原理
-
对象类型:通过Object.defineProperty()对属性的读取,修改进行拦截(数据劫持)
-
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
-
Object.defineProperty(data, 'xxx', { get() { return data[xxx]; } set() { set(value) { data[xxx] = value; } } })
-
-
存在的问题
- 新增属性,删除属性,界面不会更新。
- 解决方案:
- 新增:Vue.set(object, key, value) 或 vm.$set(object, key, value)
- 删除:Vue.delete(object, key, value) 或 vm.$delete(this.person, 'name')
- 解决方案:
- 直接通过下标修改数组,界面不会自动更新。
- 解决方案:this.$set('要修改的数组', '数组索引', '修改的值') 或 Vue.set('要修改的数组', '数组索引', '修改的值') 或 调用数组本身的方法进行响应式修改 this.arr.splice(0, 1, '修改的数据')
- 新增属性,删除属性,界面不会更新。
-
-
Vue3.0 响应式
-
实现原理
-
通过 Proxy(代理):拦截对象中任意属性变化,包括属性的读写,属性的添加,属性的删除等。
-
通过Reflect(反射):对目标对象的属性进行操作。
-
let proxy = new Proxy(data, { // 拦截读取属性值 get(target, prop) { return Reflect.get(target, prop); }, // 拦截设置属性值或添加新的属性 set(target, prop, value) { return Reflect.set(target, prop, value); }, // 拦截删除属性 deleteProperty(target, prop) { return Reflect.deleteProperty(target, prop) } }); proxy.name = '权';
-
-
-
reactive 对比 ref
-
从定义角度对比
-
ref用来定义:基本数据类型。
-
reactive用来定义:对象(或数组)类型。
-
备注:ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象。
-
import { ref } from 'vue' let person = ref({name: 'zs', age: 20}); 自动转换 ===> reactive({value: {name: 'zs', age: 20}})
-
-
-
从原理角度对比
- ref 通过 Object.definePrototype() 的 get 与 set 来实现数据响应(数据劫持)。
- reactive 通过使用 Proxy 来实现数据响应式(数据劫持),并通过Reflect操作目标对象内的数据。
-
从使用角度对比
- ref 定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
- reactive定义的数据:操作数据与读取数据:均不需要 .value
计算属性与监视
computed函数
-
与Vue2.x中computed配置功能一致。
-
import { computed } from 'vue' setup() { //.... // 计算属性-简写 let fullName = computed(()=> { return `${person.firstName}-${person.lastName}`; }) // 计算属性-完整 let fullName = computed({ get() { return `${person.firstName}-${person.lastName}`; }, set(value) { person.firstName = value.split('-')[0]; person.lastName = value.split('-')[1]; } }) }
watch 函数
- 与Vue2.x中的 watch 配置功能一致
- 两个小坑
- 监视reactive定义的响应式数据时:oldValue无法获取,强制开启了深度监视(deep配置失效)
- 监视reactive定义的响应式数据某个属性时:deep配置有效
新特性
-
Composition API(组合 API)
-
Dom 节点的挂载方式
-
setup
-
composition api其实是配合着 options选项一起使用的,因为还有name、props、components、setup这些选项。只不过是现在所有的功能都成为了一个一个的hook函数,在使用时需要手动引入,并且需要写在setup选项里面。而setup的存在就是为了让我们能够使用composition api。、
-
-
-
reactive
-
reactive是Vue3中提供的实现响应式数据的方法。
-
reactive接受一个普通对象然后返回该普通对象的响应式代理
-
setup() { const user = reactive({ name: '码农权', age: 20 }) }
-
普通对象 ==> 返回一个proxy对象
-
用user.name = "xxx" 来修改值
-
内部基于proxy实现
-
获取数据值的时候直接获取,不需要加.value
-
参数只能传入对象类型(json/arr)
- 如果给reactive传递了其他对象
- 默认情况下修改对象,界面不会自动更新
- 如果想更新,那就通过重新赋值的方式
- 如果给reactive传递了其他对象
-
-
-
ref 接受一个内部值柄返回一个响应可以变的ref对象
-
import { ref } from "vue" // 为基本数据类型添加响应状态 const name = ref('权'); // 为复杂数据类型添加响应状态 const state = ref({ count: 0 }) // 打印name的值 console.log(name.value); // 打印count的值 console.log(state.value.count)
-
任意类型 ==> 返回一个ref对象
-
用 name.value = "" 来修改值
-
获取数据值的时候需要添加.value。可以理解为ref是通过reactive包装了一层具有value属性的对象来实现的
-
参数可以传递任意类型数据,传递对象类型时也能保持深度响应式,所以适用性更广,setup中定义数据时推荐优先使用ref,方便逻辑拆分和业务解耦。
-
template中使用ref值不用通过value获取(导出后已经默认做了一个结构),js中使用ref必须通过.value获取
-
ref获取元素
-
import { ref, onMounted } from 'vue' export default { name: "Demo", setup() { const userIpt = ref(null); onMounted(()=> { userIpt.value.focus(); }); return { userIpt } } }
-
-
-
toRef
- toRef 用于为源响应式对象上的属性新建一个ref,从而保持对其源对象属性的响应式连接。
- 接受两个参数:源响应对象和属性名,返回一个ref数据。
- 例如:使用父组件传递的props数据时,要引用props的某个属性且要保持响应式连接就很有用