# vue3-dome **Repository Path**: Xbaiss/vue3-dome ## Basic Information - **Project Name**: vue3-dome - **Description**: 学习vue3的特性 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-02-03 - **Last Updated**: 2022-04-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue3-dome # 介绍 学习vue3的特性。vue3.x bate(测试版本) 发布2020年9月19日,在vue2.x的基础上进行一些优化,对typescript有更好的支持。 vue3.x语法和vue2.x非常相似。 vue3.x git地址:https://github.com/vuejs/vue-next vue3.x 文档地址:https://v3.vuejs.org # 安装vue官方脚手架以及创建项目 提供2个脚手架 创建方式,vue-cli 和vite等脚手架,推荐vue-cli vue-cli 创建项目 vue create study-vue3 (@vue/cli版本是4.5.8就有选择 vue3的默认项目 ) # 视频教程 https://www.bilibili.com/video/BV1ra4y1H7ih?p=48[尚硅谷] https://www.bilibili.com/video/BV1j5411n7m5?p=6[黑马程序员] https://www.bilibili.com/video/BV1nz4y1k7eb?p=23[it] 文档: https://www.cnblogs.com/wjlynew/p/13929818.html[深入 Vue 3 响应性原理] # vue的基本语法 ## 绑定数据,绑定html,绑定属性,循环数据 1. 绑定数据 {{mgs}} 2. 绑定HTML data(){ return { h2:"

html 标签

" } }
3. 绑定属性v-bind,简写: data(){ return { imgSrc:"../images/1.png", imgAlt:"alt" } } 动态数据: 4. 循环数据 ## 事件 ### 事件 @click ### 事件对象 eventFn(e){ //改变样式 e.srcElement.style.background="red" // 获取自定义属性的值 console.log( e.srcElement.dataset.id) //阻止默认事件 e.preventDefault() //阻止冒泡 e.stopPropagation() } 注意: @click="eventFn($event)" 这边必须是$event,方法里面的可以随便写,比如e 多个参数的话。 eventFn(msg,e){ } ### 多事件处理程序 事件间加“ ; ” methods:{ one(e) { console.log("one", e.srcElement.dataset.id); }, two($event) { console.log("two:", $event); } } ### 事件修饰符 在Vue中,事件修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。在Vue中事件修饰符主要有: .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡 .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播) .capture:与事件冒泡的方向相反,事件捕获由外到内 .self:只会触发自己范围内的事件,不包含子元素 .once:只会触发一次 跳转 这时a 就不能跳转了,只能执行fn的方法 ### 按键修饰符【非兼容】 vue3 官网: https://v3.cn.vuejs.org/guide/migration/keycode-modifiers.html#_2-x-%E8%AF%AD%E6%B3%95 常用的键提供别名: .enter .tab .delete(同时捕获删除和退格 键) .esc .space .up .down .left .right ## 双向数据绑定【 v-model】 ## 操作dom 用的ref
this.$refs.ss ## 表达式 1. 三元 {{flag=='false'?" this is false":"this is true"}} :class="[lineAnimated==false?'tab__item-title':'item']" :class="{active: (selectedCourse === c)}" :style="{backgroundColor: (selectedCourse === c)?'#ddd':'transparent'}" :style="{backgroundImage: 'url('+require(`${item}`) +')' }" :style="{transform:'rotate('+deg+'deg)'}" :style="{marginTop:$pxToRem(40),backgroundImage:'linear-gradient(#929396, #86878a)'}" 2. v-if v-else-if v-else 和v-show 区别 v-if dom 是不存在,v-show 是存在,只是隐藏而已 v-if 是dom 操作,v-show 只是css的隐藏,一般来说说,v-if有更好的切换开销,而v-show 有更高的初始渲染开销,因此,如果是需要非常频繁的切换,则使用v-show 比较好 ## 计算属性 A值的改变 是因B值,或是更多的值的改变而改变 ,这时可以采用 计算属性 ## watch 监听数据变化 观察vue实例上的数据变动, 简单的理解就是监听data,props的里面值的前后变化 ## watch,computed区别 1. computed 定义了就不能定义在data,props,所以一般是vuex中的state用,watch是针对data,props的变量进行监听 2. computed是针对新变量,watch是针对已经存在的变量 3. computed是 A值的改变 是因B值,或是更多的值的改变而改变;watch 是观察vue实例上的数据变动, 简单的理解就是监听data,props的里面值的前后变化 ## 组件 单文件组件:就是模块的组件,my-home 定义组件 注册组件/挂载组件 components: { my-home } ## vue 传值 A. 父 子 传值 使用props接受 props 可以直接用 默认类型 props:{ list:{ type:Array , default: () => [1, 2, 3, 4, 5] } } 或是: props:['list'] vue props 传递函数: methods: { childrenClick(c){ console.log(c,'子组件传递过来') } }, // 子组件 export default { data() { return { count:1, } }, props:{ add:{ type: Function } }, methods: { handClick(){ this.add( ++this.count); // 父组件方法 } }, } this 传值: home:
data() { return { count:1, name:"黄小" } }, methods: { handClick(){ this.add( ++this.count); // 父组件方法 } }, header:
{{home.name}}
这边可以获取home组件 的data和methods 补充:props 验证 props:{ list:{ type:Array , default: () => [1, 2, 3, 4, 5] }, num:{ type:String } } // 如果 num 是字符串 如果传数字,那这样就会报错,只能传字符串 B.子 父 传值 父亲写事件函数 子 $emit触发 传值 父: callValFn(item) { console.log("items:", item); }, 子: getName() { let val ="$emit 传值"; this.$emit("call-val", val); }, C.兄弟传值 $bus 中转站 D.如果组件之间 关系很远 是很多组件都要用的值 vuex 补充: 父组件主动获取子组件的数据,方法 base.vue data() { return { msg: "父组件", }; }, //父组件主动获取子组件的数据,方法 getChildFn() { console.log(this.$refs.headerRef.name, "ssss ddd"); this.$refs.headerRef.getName(); }, fatherFn() { console.log("父组件的方法"); }, 子组件主动获取父组件的数据,方法 headers.vue # vue3 ## 非父子组件传值 使用mitt 插件 【https://github.com/developit/mitt】 1. 安装插件:npm install --save mitt 2. 引入插件: src/ model/event.js // using ES6 modules import mitt from 'mitt' const event = mitt() export default event 3. mitt 组件 4. headers ## 新特性 ## 组合式 API 也就是composition-api (1) vue2 组件的局限性 1. 组件越大,可续性越差 2. 相同的代码逻辑很难在多个组件中复用 ### composition-api优点 1. 提供了更完善的ts支持 2. 组件拥有了更加良好的代码组织结构 3. 相同的代码逻辑在不同的组件中进行了完整的复用 ### 提供以下几个函数 1. setup :组合api 的方法都是写在这里面的 2. ref : 定义响应式数据 字符串 bool 3. reactive :定义响应式数据 对象 4. watchEffet :监听数据变化 5. watch :监听数据变化 6. computed :计算属性 7. toRefs :解构响应式对象数据 8. 生命周期的hooks #### setup https://v3.cn.vuejs.org/guide/composition-api-setup.html#%E5%8F%82%E6%95%B0 1. setup 函数会在 beforeCreate、created 之前执行,setup的生命周期 在 beforeCreate、created 之后执行 2. setup 有2个参数 props 的父组件传递过来的参数 ctx 上下文对象 ctx.attrs ctx.slots ctx.parent ctx.root ctx.emit ctx.refs 3. 在 setup() 函数中无法访问到 this【没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。】 4. 执行 setup 时,组件实例尚未被创建,你只能访问以下 property【props,attrs, slots, emit 】,你将无法访问以下组件选项【data,computed ,methods】 #### ref ,reactive 定义响应式数据 ref 【定义字符串,num,bool,数组】 reactive【定义对象】 使用 ref 还是 reactive 可以选择这样的准则 第一,就像刚才的原生 javascript 的代码一样,像你平常写普通的 js 代码选择原始类型和对象类型一样来选择是使用 ref 还是 reactive。 第二,所有场景都使用 reactive,但是要记得使用 toRefs 保证 reactive 对象属性保持响应性 第三, 一般ref定义字符串,num ,布尔型,数组;reactive 定义的是对象 reactive 相当于 Vue 2.x 中的 Vue.observable() API ref https://v3.cn.vuejs.org/guide/reactivity-fundamentals.html#ref-%E5%B1%95%E5%BC%80 声明响应式状态: ref reactive 这就是 Vue 响应性系统的本质: 该 API 返回一个响应式的对象状态。该响应式转换是“深度转换”——它会影响嵌套对象传递的所有 property #### toRefs 解构响应式对象数据

2.toRefs 解构响应式对象数据

{{worksName}} setup() { // 2.toRefs 解构响应式对象数据 var worksInfos = reactive({ worksName: "张三", worksDesi: "到好多好好的" }); return { ...toRefs(worksInfos) //...worksInfos 这样的话可以显示数据,但是不能双向绑定数据 }; } #### computed 计算属性 【只能在setup】
{{fullName}}
setup() { //3.computed :计算属性 var userInfos2 = reactive({ firstName: "王", lastName: "一搏" }); var fullName = computed(() => { return userInfos2.firstName + userInfos2.lastName; }); return { ...toRefs(userInfos2), fullName }; #### readonly "深层"的只读代理 (少用) 将响应式 数据(ref,reactive定义的数据),转正非响应式的数据(也就是原始数据) readonly 传入一个对象(响应式对象),返回一个原始对象 只能读取不能修改。 var obj={ username:"李小英" } obj 就是原始数据, 可以渲染在页面中,但是不能双向绑定 var userInfos = reactive({ username: "张三", age: 20 }); userInfos 响应式数据, 可以把响应式数据 转成非响应式数据, const copy = readonly(userInfos) //copy.username 只能读取,不能修改 #### watchEffet 监听数据变化 在响应式地跟踪其依赖项时,立即运行一个函数,并在更改依赖项时重新运行它。

4.watchEffet 监听数据变化 --侦听器

{{data.count}}
const data = reactive({ count: 1, num: 1 }); const stop = watchEffect(() => { console.log("侦听器:", data.count); }); setInterval(() => { data.count++; }, 1000); #### watch , watch与watchEffect区别 (1).watch与watchEffect区别: const data = reactive({ count: 10, num: 1 }); 1. 懒执行,也就是说只有侦听的值变更时才执行回调 watchEffect(() => { console.log("侦听器:", data.count);// 可以输出1 }); watch(data, () => { console.log("watch 监听:", data.count);// 输出2 }); watch 只有监听到值(data.count)发生变化 才执行,watchEffect都可以执行 2. 更明确哪些状态的改变会触发侦听器重新运行 watchEffect 可以监听具体的对象【如:data.count】,watch 只能监听ref或是reactive定义的对象【如: data】 3. 访问侦听状态变化前后的值 watch(numVal, (newVal, oldVal) => { console.log("numVal新值跟旧值的变化:", newVal, oldVal); }); (2). eg:

5.watch 监听数据变化 --侦听器

{{data.count}}
watch 双向数据绑定,前后数据
{{numVal}} const data = reactive({ count: 10, num: 1 }); // (1).简单的引用 // 要监听对象data ,但是不能监听对象里的值data.count watch(data, () => { console.log("watch 监听:", data.count); }); setInterval(() => { data.count++; }, 1000); var numVal = ref("1"); // (2).watch 的两个参数,代表新的值和旧的值 watch(numVal, (newVal, oldVal) => { console.log("numVal新值跟旧值的变化:", newVal, oldVal); }); //(3). watch 多个值,返回的也是多个值的数组 watch([numVal, data], (newValue, oldValue) => { console.log("old", oldValue); //["13",Proxy {count: "144", num: 1}] console.log("new", newValue); //["134",Proxy {count: "144", num: 1}] }); // (4).使用 getter 的写法 watch reactive 对象中的一项 watch([numVal, () => data.count], (newValue, oldValue) => { console.log("old", oldValue); //old (2) ["1", 10] console.log("new", newValue); //new (2) ["1", "103"] console.log("updated:" + numVal.value + data.count); //updated:1103 }); #### 生命周期 https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html 都是 setup () 内部调用生命周期钩子,没有beforeCreate,created ,其他都是一样 在生命周期的vue3更新: 在vue3中对生命周期钩子的命名进行一些简单的命名更新,并且在setup函数中提供了新的生命周期函数钩子。 1. 命名改变: vue3对beforeDestroy 和destroy进行命名的修改,分别修改为beforeUnmount,unmounted。这个是命名的改变,回调时机上并没有发生任何的改变。 2. setup函数中提供了新的生命周期函数钩子 https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html ### Provide / Inject https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E8%AE%BE%E6%83%B3%E5%9C%BA%E6%99%AF 不管组件层次 结构多深,都可以使用这个Provide(传递参数) / Inject (接受参数) ### 非组合api app.vue provides: location.vue: 点击fn,不能改变location.vue的值,就是没有响应的效果 没有办法 双向绑定 ### 组合api (重点) https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html#%E4%BD%BF%E7%94%A8-provide provides: location.vue: ### 总结: 1.祖父组件定义provide,孙组件inject接受 2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件 ### 不想子组件改变父组件的数据 最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly provide("userInfos", readonly(userInfos)); ## 模板引用【template refs】 当使用组合式 API 时,响应式引用【reactive refs】 和 模板引用【template refs】 的概念已经是统一的。 ## 响应性 ### 比较vue2 和 vue3 响应式 #### vue2 的响应式: 核心: 对象:通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视、拦截) 数组:通过重写数组更新数组一系列更新元素的方法实现元素修改的劫持【简单的理解:普通数组变成响应数组,对一个数组的元素进行更改的话,它会对这个更改的方法进行重新编写】 object.defineProperty(data,'count',{ get(){}, set(){} }) 问题: 1. 对象直接新添加的属性或删除已有属性,界面不会自动更新 2. 直接通过下标替换元素或更新length,界面不会自动更新 arr[1] ={} 所以后面才有$set,去响应数据 eg:
{{key}}:{{val}}
//因为vue2 是通过object.defineProperty 来操作数据,所以不能检测数据的变动(虽然打印出来的数据是更新的,但是界面的数据没更新) export default { data() { return { user: { name: "王一博", age: 20 } }; }, methods: { add() { this.user.sex = "男"; console.log( this.user); } } }; 注意同样的代码在vue3 里面就可以。不旦数据更新,界面也更新。原因是vue3使用prory #### vue3 的响应式: 核心: 1.通过proxy(代理):拦截对data任意属性的任意(13种)操作,包括属性值的读写,属性的添加,属性的删除等 2.通过reflect(反射):动态对被代理对象的相应属性进行特定的操作 ### 什么是响应式 响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。 简单的理解:对对象进行修改,对象数据会改变,界面上也会发生改变 ### 深入vue3响应性原理 就是把目标对象变成代理对象(prory),然后通过代理对象对数据进行操作,通过reflect在反射回来。 ### 什么是prory proxy 是一个对象,可以代理一个对象或函数,允许拦截被代理的对象或函数 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy[proxy] ### Reflect https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect[reflect] ## 有意思的Teleport https://v3.cn.vuejs.org/guide/teleport.html[官网] teleport 是vue3 内置组件,接受2个函数(to:指定将在其中移动 内容的目标元素 如:body,.home ,#home;disabled :禁止使用该功能) 请注意,这将移动实际的 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。 核心就是to的操作 ## 注意点 ### 值得注意的新特性 Vue 3 中需要关注的一些新功能包括: 组合式 API Teleport 片段 触发组件选项 来自 @vue/runtime-core 的 createRenderer API 创建自定义渲染器 单文件组件组合式 API 语法糖 (