vue 2.0代码混淆(Vue2进阶笔记)
Vue2进阶笔记 ,受益于尚硅谷天禹老师课程 ,在此表示感谢 ,全文共三万余字 。
一 、基础知识
tips:
1 、所被Vue管理的函数 ,最好写成普通函数 ,这样this的指向才是vm或组件实例对象 。
2 、所有不被Vue所管理的函数(定时器的回调函数 、ajax的回调函数 、Promise的回调函数等) ,最好写成箭头函数这样this的指向才是vm或组件实例对象 。1.1 computed计算属性
在computed中 ,可以定义一些属性 ,即计算属性 。计算属性具有缓存
功能 ,相比较methods效率更高 。
计算属性本质是方法 ,只是在使用这些计算属性的时候 ,把他们的名称直接当作属性来使用 ,并不会把计算属性当作方法去调用,不需要加小括号()调用 。
计算属性的求值结果会被缓存起来 ,方便下次直接使用(多次调用只要内部数据不改变就不会重新求值 ,改变了也只会计算一次,虽然有多个地方引用此属性) 。getter方法内部无论如何都要return出去一个值 。 <body> <div id="app"> <h1>计算属性:computed的getter/setter</h1> <br/> 姓:<input type="text" v-model="firstName"> <br/> 名:<input type="text" v-model="lastName"> <br/> 全名:<input type="text" v-model="fullName">> </div> <script> var app = new Vue({ el:"#app", data:{ firstName:"zhang", lastName:"san", }, computed: { /* 完全写法 ,可读可修改 fullName:{ get:function(){ return this.firstName + "-" + this.lastName }, set:function(value){ var list = value.split( ); this.firstName=list[0] this.lastName=list[1] } } */ // 只读不修改 ,只有getter没有setter ,简写 fullName(){ return this.firstName + "-" + this.lastName } }, }); </script> </body>注意:计算属性可以传参 ,但是不能直接传参 。
但是在实际开发中我们会更多地使用计算属性 ,因为计算属性会进行缓存 ,多次使用时 ,计算属性只会调用一次 。
<p>班级:{{ getClassName(item.faceClass) }}</p> // ... // 正确写法 返回的是一个函数 computed: { getClassName() { return function (classId) { const element = this.classList; for (let index = 0; index < element.length; index++) { if (element[index].classId == classId) { return element[index].className; } } }; }, },如果直接传参则会提示错误:>TypeError: songerName is not a function
// 错误写法 computed: { songName(classId) { const element = this.classList; for (let index = 0; index < element.length; index++) { if (element[index].classId == classId) { return element[index].className; } } } }1.2 watch监视属性
Watch概述
一个对象 ,键是需要观察的表达式 ,值是对应回调函数 。值也可以是方法名 ,或者包含选项的对象 。Vue 实例将会在实例化时调用 $watch() ,遍历 watch 对象的每一个属性。
深度监视:
(1). Vue中的watch默认不监测对象内部值的改变(一层) 。
(2). 配置deep:true可以监测对象内部值改变(多层) 。
备注:
(1). Vue自身可以监测对象内部值的改变 ,但Vue提供的watch默认不可以!
(2). 使用watch时根据数据的具体结构,决定是否采用深度监视。简单的监听
<body> <div id="app"> <input type="text" v-model="num"> </div> <script src="vue.js"></script> <script> const vm = new Vue({ el: #app, data: { num: }, // 创建vue实例时就知道需要监视那个数据项,用这种方法 watch: { // 不考虑immediate和deep只有hander一个配置项时 ,可以简写 num(newVal, oldVal) { // 监听 num 属性的数据变化 // 作用 : 只要 num 的值发生变化,这个方法就会被调用 // 第一个参数 : 新值 // 第二个参数 : 旧值,之前的值 console.log(oldVal:,oldVal) console.log(newVal:,newVal) } }, // 正常写法 根据用户行为 ,方才知道那个数据项需要监视,用这种方法 vm.$watch(num,{ // 每个属性值发生变化就会调用这个函数 handler(newVal, oldVal) { console.log(oldVal:, oldVal) console.log(newVal:, newVal) }, // 立即处理 进入页面就触发 immediate: true, // 深度监听 监视多级结构中所有属性的变化 deep: true } }) // 不考虑immediate和deep只有hander一个配置项时 ,可以简写 vm.$watch(num,function(newVal, oldVal) { console.log(oldVal:, oldVal) console.log(newVal:, newVal) }) </script> </body>immediate(立即处理 进入页面就触发)
deep(深度监听)
对象和数组都是引用类型 ,引用类型变量存的是地址 ,地址没有变 ,所以不会触发watch 。这时我们需要进行深度监听 ,就需要加上一个属性 deep ,值为 true 。 <body> <div id="app"> <input type="button" value="更改名字" @click="change"> </div> <script src="vue.js"></script> <script> new Vue({ el: #app, data: { food: { id: 1, name: 冰激凌 } }, methods: { change() { this.food.name = 棒棒糖 } }, watch: { // 完整写法 // 第一种方式:监听整个对象 ,每个属性值的变化都会执行handler // 注意:属性值发生变化后 ,handler执行后获取的 newVal 值和 oldVal 值是一样的 food: { // 每个属性值发生变化就会调用这个函数 handler(newVal, oldVal) { console.log(oldVal:, oldVal) console.log(newVal:, newVal) }, // 立即处理 进入页面就触发 immediate: true, // 深度监听 监视多级结构中所有属性的变化 deep: true }, // 第二种方式:监听对象的某个属性 ,被监听的属性值发生变化就会执行函数 // 函数执行后 ,获取的 newVal 值和 oldVal 值不一样 food.name(newVal, oldVal) { console.log(oldVal:, oldVal) // 冰激凌 console.log(newVal:, newVal) // 棒棒糖 } } }) </script> </body>Watch和computed的区别
1 、 computed支持缓存 ,只有依赖数据发生改变 ,才会重新进行计算;而watch不支持缓存,数据变 ,直接会触发相应的操作 。
2 、computed不支持异步 ,当computed内有异步操作时无效,无法监听数据的变化 ,而watch支持异步 。
3 、computed属性值会默认走缓存 ,计算属性是基于它们的响应式依赖进行缓存的 ,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值;而watch监听的函数接收两个参数 ,第一个参数是最新的值 ,第二个参数是输入之前的值 。
4 、如果一个属性是由其它属性计算而来的 ,这个属性依赖其它属性 ,多对一或者一对一 ,一般用computed;而当一个属性发生变化时 ,需要执行对应的操作 ,一对多 ,一般用watch 。1.3 动态绑定样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>绑定样式</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> <style> .basic{ width: 400px; height: 200px; border: 2px solid cornflowerblue; } .normal{ background-color: lightsteelblue; } .happy{ background-color: cornflowerblue; } .sad{ background-color: chartreuse; } .test1{ font-size: 20px; text-align: center; } .test2{ border-radius: 10px; } .test3{ font-style: inherit; background-color: red; } </style> </head> <body> <!-- 准备好一个容器 --> <div id="root" > <!-- 绑定class样式 ,字符串写法 。适用于:样式的类名不确定,需要动态绑定 --> <div class="basic" :class="mood" @click="changeMood">{{name}}></div><br><br> <!-- 绑定class样式 ,数组写法 。适用于:要绑定的个数不确定 ,名字也不确定 --> <div class="basic" :class="arr" >{{name}}></div><br><br> <!-- 绑定class样式,对象写法 。适用于:要绑定的个数不确定 ,名字也不确定 --> <div class="basic" :class="classObj" >{{name}}></div><br><br> <!-- 绑定style样式 ,对象写法 。 --> <div class="basic" :style="styleObj" >{{name}}></div><br><br> <!-- 绑定style样式 ,数组写法 ,使用较少 。 --> <div class="basic" :style="styleArr" >{{name}}></div><br><br> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示 new Vue({ el:"#root", data:{ name:"才疏学浅", mood:normal, arr:[test1,test2,test3], classObj:{ test1:false, test2:false, test3:false }, styleObj:{ // 这里的属性名要遵循驼峰命名规范 font-size --> fontSize fontSize: 40px, color: blue }, styleArr:[ { fontSize: 40px, color: blue }, { backgroundColor: red } ] }, methods: { changeMood(){ const arr = [normal,happy,sad] this.mood = arr[Math.floor(Math.random()*3)] } }, }) </script> </html>1.4 列表循环渲染 key的探讨
当数组数据有可能顺序被破坏时 ,采用数组index作为key值可能导致:输入框内容错乱 、效率过低的情况 。当不写key时 ,vue会自动将数组的index索引值作为key值进行deff虚拟DOM对比算法。
采用数组自带id属性 ,则不会出现这种情况 。
面试题:react 、vue中的key有什么作用?(key的内部原理)
1 、虚拟DOM中key的作用:
key是虚拟DOM对象的标识 ,当状态中的数据发生变化时 ,Vue会根据【新数据】生成【新的虚拟DON】 ,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较 ,比较规则如下:2、对比规则:
(1). 旧虚拟DOM中找到了与新虚拟DOM相同的key:
若虚拟DOM中内容没变 ,直接使用之前的真实DOM 。
若虚拟DOM中内容变了,则生成新的真实DOM ,随后替换掉页面中之前的真实DOM。
(2). 旧虚拟DOM中未找到与新虚拟DOM相同的key:
创建新的真实DOM,随后渲染到到页面 。3 、用index作为key可能会引发的问题:
若对数据进行:逆序添加 、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 – > 界面效果没问题 ,但效率低 。
如果结构中还包含输入类的DOM:会产生错误DOM更新 – > 界面有问题 。4、开发中如何选择key? :
最好使用每条数据的唯一标识作为key,比如id 、手机号 、身份证号 、学号等唯一值 。
如果不存在对数据的逆序添加 、逆序删除等破坏顺序操作 ,仅用于渲染列表用于展示 ,使用index作为key是没有问题的 。1.5 列表过滤
监视(侦听)属性实现列表过滤:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!--引入Vue--> <script type="text/javascript" src="../js/vue.js"></script> <title></title> </head> <body> <!--准备好一个容器--> <div id="root"> <input type="text" placeholder="请输入名字" v-model="keyWord"> <ul> <li v-for="p in filPersons" :key="p.id"> {{p.name}}-{{p.age}}--{{p.sex}} </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false; new Vue({ el: #root, data: { keyWord: , persons: [ { id: 001, name: 马冬梅, age: 19, sex: 女 }, { id: 002, name: 周冬雨, age: 20, sex: 女 }, { id: 003, name: 周杰伦, age: 21, sex: 男 }, { id: 003, name: 温兆伦, age: 22, sex: 男 } ], filPersons: [] }, watch: { keyWord: { immediate: true, handler(val) { this.filPersons = this.persons.filter((p) => { return p.name.indexOf(val) !== -1 }) } } } }) </script> </body> </html>用计算属性实现列表过滤:
computed:{ filPersons(){ return this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord)!==-1 }) } }用计算属性实现过滤 ,同时需要列表排序:
computed:{ filPersons(){ const arr= this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord)!==-1 }) //判断一下是否需要排序 if(this.sortType){ arr.sort((a,b)=>{ return this.sortType===1?b.age-a.age:a.age-b.age }) } return arr } }1.6 数据监视
Vue会监视data中所有层次的数据 。通过setter实现监视 ,且在new Vue时就传入要监测的数据 。
对象中后追加的属性 ,Vue默认不做响应式处理 。如需给后添加的属性做响应式 ,请使用如下API:
Vue.set(target,prpertyName/index,value) vm.$set(target,prpertyName/index,value)通过包裹数组更新元素的方式实现监测数组中的数据 ,本质是:1. 调用原生对应的方法对数组进行更新 。2. 重新解析模板 ,进而更新页面 。
在Vue修改数组中的某个元素时一定要使用如下方法:
1 、使用API:push() 、pop() 、shift() 、unshift() 、splice() 、sort() 、reverse()
2 、使用 Vue.set或者vm.$set(this.$set)注意:Vue.set和vm.$set不能给vm或vm的根数据对象添加属性 。
1.7 表单收集
v-model默认收集的是表单的value值 ,这里有几个需要主要的点 。
若<input type="text"/> ,则v-model收集的是value值 ,用户输入的就是value值。 若<input type="radio"/> ,则v-model收集的是value值,且要给标签配置value值 。 若<input type="checkbox"/> 1、没有配置input的value属性 ,那么收集的就是checked(勾选 or 未勾选 ,布尔值) 2 、配置了input的value属性 v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选 ,布尔值) v-model的初始值是数组 ,那么收集的就是value组成的数组 。备注:v-model的三个修饰符:
1 、lazy:失去焦点后再收集数据。
2、number:输入字符串转为有效的数字 。
3 、trim:输入首尾空格过滤 。1.8 过滤器
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理) 。
// 语法: 注册过滤器:Vue.filter(name,callback)或new Vue{filters:{}} 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"备注:
过滤器也可以接收额外参数 ,多个过滤器能够串联 。
并没有改变原本的数据 ,是产生新的对应的数据 。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>过滤器</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> <script type="text/javascript" src="../js/dayjs.min.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <h2>显示格式化后的时间</h2> <!-- 计算属性实现 --> <h3>(计算属性实现)现在是{{fmtTime}}</h3> <!-- methods实现 --> <h3>(methods实现)现在是{{getfmtTime()}}</h3> <!-- 过滤器实现 --> <h3>(过滤器实现)现在是{{time | timeFormater}}</h3> <!-- 过滤器传参 --> <h3>(过滤器传参)现在的日期是{{time | timeFormater(YYYY年_MM月_DD日)}}</h3> <!-- 多个过滤器传参 --> <h3>(多个过滤器传参)今年是{{time | timeFormater(YYYY年_MM月_DD日) | mySlice}}</h3> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示 // 全局过滤器 Vue.filter(mySlice,function(value){ return value.slice(0,5) }) new Vue({ el:#root, data:{ name:才疏学浅的小缘同学, time: 1647417712099 }, computed:{ fmtTime(){ return dayjs(this.time).format(YYYY年-MM月-DD日 HH:mm:ss) } }, methods: { getfmtTime(){ return dayjs(this.time).format(YYYY年-MM月-DD日 HH:mm:ss) } }, // 局部过滤器 filters:{ timeFormater(value,str=YYYY年-MM月-DD日 HH:mm:ss){ return dayjs(value).format(str) }, } }) </script> </html>1.9 生命周期函数
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如 ,需要设置数据监听 、编译模板 、将实例挂载到 DOM 并在数据变化时更新 DOM 等 。同时在这个过程中也会运行一些叫做生命周期的函数 ,这给了用户在不同阶段添加自己的代码的机会 。
beforeCreate(创建前) created (创建后) beforeMount (载入前) mounted (载入后) beforeUpdate (更新前) updated (更新后) beforeDestroy( 销毁前) destroyed (销毁后)Vue生命周期函数就是vue实例在某一个时间点会自动执行的函数
当Vue对象创建之前触发的函数(beforeCreate) Vue对象创建完成触发的函数(Created) 当Vue对象开始挂载数据的时候触发的函数(beforeMount) 当Vue对象挂载数据的完成的时候触发的函数(Mounted) 当Vue对象中的data数据发生改变之前触发的函数 (beforeUpdate) 当Vue对象中的data数据发生改变完成触发的函数(Updated) 当Vue对象销毁之前触发的函数 (beforeDestroy) 当Vue对象销毁完成触发的函数(Destroy)1.10 nextTick
语法:this.$nextTick(回调函数) 作用:在下一次DOM更新结束后执行其指定的回调 。 什么时候用:当改变数据后 ,要基于更新后的新的DOM进行某些操作时 ,要在nextTick所指定的回调函数中执行 。1.11 动画与过渡
指定过渡动画的步骤:
在目标元素外面包裹
指定过渡样式:transition(css3的属性)
指定隐藏时的样式:opacity/或者其他(width等等) 如果有多个元素需要过渡 ,则需要使用:<<transition-group> ,并且每个元素都要指定key值 。 <transition name="xxx"> <h1>你好</h1> </transition> 其他的第三方库/animate.style ,官网有文档 ,自行学习 。过渡的相关类名:
xxx-enter-active:指定显示的 transition
xxx-leave-active:指定隐藏的 transition
xxx-enter/xxx-leave-to:指定隐藏时的样式 <style> /*入场动画规则*/ @keyframes boxenter { 0% { transform: translateX(-100px); } 100% { transform: translateX(0); } } /*出场动画规则*/ @keyframes boxleave { 0% { transform: translateX(0); } 100% { transform: translateX(-100px); } } /*这里应用入场动画规则*/ .v-enter-active { animation: boxenter 3s; } /*这里应用出场场动画规则*/ .v-leave-active { animation: boxleave 3s; } </style> <body> <div id="app"> <button @click="change">切换</button> <!-- 使用transition标签包装需要动画的元素 --> <transition> <mycomponent v-if="isShow"></mycomponent> </transition> </div> ... </body> <style> /* demo1 */ /* 显示/隐藏的过渡效果 */ .xxx-enter-active,.xxx-leave-active{ transition: opacity 1s; } /* 隐藏时的样式 */ .xxx-enter,.xxx-leave-to{ opacity: 0; } /* demo2 */ /* 显示的过渡效果 */ .yyy-enter-active{ transition: all 1s; /* transform: translateX(20px); */ } /* 隐藏时的过渡效果 */ .yyy-leave-active{ transition: all 3s; } /* 隐藏时的样式 */ .yyy-enter,.yyy-leave-active{ opacity: 0; transform: translateX(20px); } </style> <body> <div id="demo1"> <button @click="isShow = !isShow">Toggle</button> <transition name="xxx"> <p v-show="isShow">hello</p> </transition> </div> <div id="demo2"> <button @click="isShow = !isShow">Toggle</button> <transition name="yyy"> <p v-show="isShow">hello</p> </transition> </div> <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> <script> new Vue({ el:"#demo1", data:{ isShow:true } }) new Vue({ el:"#demo2", data:{ isShow:true } }) </script> </body>1.12 脚手架配置跨域代理
方法一: 在vue.config.js中添加如下配置:
devServer:{ proxy:http://localhost:服务器端口 }说明:
优点:配置简单,请求资源时直接发给前端(8080)即可 。 缺点:不能配置多个代理 ,不能灵活的控制请求是否走代理。 工作方式:若按照上述配置代理 ,当请求了前端不存在的资源(public目录下资源)时,那么该请求会转发给服务器(优先匹配前端资源)方法二: 编写vue.config.js配置具体代理规则:
module.exports = { devServer: { proxy: { "/api": { // 匹配所有以/api开头的请求路径 target: "http://localhost:5000", // 代理目标的基础路径 changeOrigin: true, // 用于控制请求头中的host值 pathRewrite: { "^/api": "" }, }, "/other": { // 可以配置多个代理路径 target: "http://localhost:5001", changeOrigin: true, pathRewrite: { "^/other": "" }, }, }, }, }; /** * changeOrigin设置为true时 ,服务器收到的请求头中的host为: localhost:5000 * changeOrigin设置为false时 ,服务器收到的请求头中的host为: localhost:8080 * changeorigin默认值为true */说明:
优点:可以配置多个代理 ,且可以灵活的控制请求是否走代理 。 缺点:配置略微繁琐 ,请求资源时必须加前缀 。二 、组件化开发
2.1 演替与定义
组件的定义:实现应用中局部功能代码和资源的集合。
2.2 使用与注册
组件化编码流程:
拆分静态组件:组件要按照功能点拆分 ,命名不要与html元素冲突 。 实现动态组件:考虑好数据的存放位置 ,数据是一个组件在用 ,还是一些组件在用:
(1)一个组件在用:放在组件自身即可 。
(2)一些组件在用:放在他们共同的父组件上(状态提升) 。 实现交互:从绑定事件开始 。组件的使用分为:非单文件组件 、单文件组件 。区别是否将单个html文件解耦为多个vue文件 。
标准化开发中 ,我们会创建一个 app 组件去管理(领导)下属的所有组件 ,最顶级的vm管理app 。(一人之下万人之上) <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>几个注意点</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 几个注意点: 1.关于组件名: 一个单词组成: 第一种写法(首字母小写):school 第二种写法(首字母大写):School 多个单词组成: 第一种写法(kebab-case命名):my-school 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持) 备注: (1).组件名尽可能回避HTML中已有的元素名称 ,例如:h2 、H2都不行 。 (2).可以使用name配置项指定组件在开发者工具中呈现的名字 。 2.关于组件标签: 第一种写法:<school></school> 第二种写法:<school/> 备注:不用使用脚手架时 ,<school/>会导致后续组件不能渲染 。 3.一个简写方式: const school = Vue.extend(options) 可简写为:const school = options --> <!-- 准备好一个容器--> <div id="root"> <h1>{{msg}}</h1> <school></school> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义组件 const s = Vue.extend({ name:atguigu, template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> `, data(){ return { name:尚硅谷, address:北京 } } }) new Vue({ el:#root, data:{ msg:欢迎学习Vue! }, components:{ school:s } }) </script> </html>2.3 VueComponent
组件本质其实是一个名为VueComponent的构造函数 ,且不是由程序员来定义的,是由Vue.extend生成的 。
当我们写出组件名作为标签时 ,Vue解析会自动帮我们创建该组件名的对象实例并且执行new VueComponent(options) 。 每次调用Vue.extend 返回的都是一个新的 VueComponent 学过后端的应该很清楚。 在组件中的this所指向的是 VueComponent 类似于java的动态绑定 。组件实例对象(vc)可以访问到Vue原型上的属性 、方法 。
2.4 vue-cli脚手架
脚手架文件结构
更正:App.vue 文件名默认是可以更改的 ,只不过不推荐。
脚手架文件目录 // 当引入第三方公共css库,使用import导入存在报错(import会严格检查) ,可将css库放在public目录下 ,在index.html主页面通过link引入 。 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │── App.vue: 汇总所有组件 │ └── main.js: 入口文件 ├── .gitignore: git版本管制忽略的配置 ├── babel.config.js: babel的配置文件 ├── package.json: 应用包配置文件 ├── README.md: 应用描述文件 └── package-lock.json: 包版本控制文件报错信息:error Component name “School ” should always be multi-word vue/multi-word-component-names
报错原因:自己在给组件命名时没有使用推荐的大驼峰或者’-拼接单词 ,所以编译的时候报错 ,实际上是语法检测的问题vue.config.js
const { defineConfig } = require("@vue/cli-service"); module.exports = defineConfig({ transpileDependencies: true, // 关闭语法检测 lintOnSave: false, }); 为什么要写那么多版本的vue包,因为模板解析器占体积太大了,大概占整个Vue源码的1/3 。 开发时没问题,但是在上线生产时, 这个模板解析器太大且没有必要打包 ,为了精简与优雅 ,尤雨溪给我们提供了不同阶段使用不同版本的Vue 。 关于不同版本的Vue: 1.vue.js 与vue.runtime.xxx.js的区别: (1).vue.js是完整版的Vue ,包含:核心功能+模板解析器 。 (2).vue.runtime.xxx.js是运行版的Vue ,只包含:核心功能;没有模板解析器 。 2.因为vue.runtime.xxx.js没有模板解析器 ,所以不能使用template配置项 ,需要使用render函数接收到的createElement函数去指定具体内容2.5 main.js中的render
为什么会用render不用template, 因为 默认引入的Vue => import Vue from vue 是残缺版的 ,完整版在vue/dist/vue这个里面包含模板解析器 。
默认脚手架生成的main.js入口文件
import Vue from "vue"; import App from "./App.vue"; // 创建vm new Vue({ // 完成这样的功能:将App组件挂载到容器中 。类似于 template:‘<App></App>’ 的作用 ,但这里不能使用template 。 render: (h) => h(App) }).$mount("#app"); // 关闭Vue生产提示 // Vue.config.productionTip = false实际上等同于下列写法:
import Vue from "vue"; import App from "./App.vue"; new Vue({ el: "#app", // createElement是一个形参 render(createElement) { return createElement(App); }, }); // Vue.config.productionTip = false2.6 ref属性
ref是Vue提供的操作DOM的属性,相比于js中给标签添加id ,在通过document.getElementById()获取DOM ,可以直接获取子组件标签的实例对象 。作用如下:
被用来给元素或子组件注册引用信息(id的替代者) 。 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc) 。 使用方式:
打标识:
.....
或 获取:this.$refs.xxx <template> <div> <h1 ref="title">nihao</h1> <School ref="school"></School> <Student></Student> <button @click="showDom">点我提示DOM</button> </div> </template> <script> import School from ./components/School.vue; import Student from ./components/Student.vue; export default { components: { School, Student }, methods: { showDom() { console.log(this.$refs); } } } </script> <style> </style>2.7 props配置
props功能是让组件接收外部传过来的数据 。props是只读的 ,Vue底层会监测你对props的修改 ,如果进行了修改 ,就会发出警告。注意:由于props的渲染等级高于data ,若业务需求确实需要修改 ,那么请复制props的内容到data中一份 ,然后去修改data中的数据 。
props适用于:
父组件 ==> 子组件 通信 子组件 ==> 父组件 通信 (要求父先给子一个函数)注意:
使用v-model时要切记:v-model绑定的值不能是props传过来的值 ,因为props是不可以修改的! props传过来的若是对象类型的值 ,修改对象中的属性时Vue不会报错 ,但不推荐这样做 。父组件App
<template> <div> <Student name="zs" sex="男" :age="19"></Student> </div> </template>子组件Student
<template> <div> <h2>{{ msg }}</h2> <h1>学生名称:{{ name }}</h1> <h1>学生性别:{{ sex }}</h1> <h1>学生年龄:{{ age }}</h1> </div> </template> <script> export default { // 1 、简单声明接收 props: [name, sex, age], // 2 、接收的同时对数据类型进行限制 props:{ name:String, age:Number, sex:String } // 3 、接收的同时对数据类型限制+默认值指定+必要性限制 props:{ name:{ type:String, // name的类型必须是String required:true // name值是必要的 }, age:{ type:Number, default:99 }, name:{ type:String, required:true } } data() { return { msg: hello,world } } } </script> <style> </style>2.8 mixin混入
mixin用于抽取公共的配置项为混入对象。通过import xxx from ...导入 与 mixins:[xxx,...]将抽取出来的配置与自身配置进行整合 。
当配置出现冲突时 ,生命周期函数来者不拒 ,混合在前自身在后 。除生命周期函数之外的配置以自身配置为主 ,覆盖掉混合配置 。
EX:Student.vue与School.vue中都有公共的showName()方法,可以抽取为mixin.js // mixin.js export const mixin = { // 除了methods,还可以配置data 、 mounted等等诸多配置 。 methods: { showName() { alert(this.name); }, } };School.vue
<template> <div> <h1 @click="showName">学校名称:{{ name }}</h1> <h1>学校地址:{{ address }}</h1> </div> </template> <script> // 1 、引入 import { mixin } from ../mixin export default { data() { return { name: 希望小学, address: 北京北京 } }, // 2、通过mixins配置 mixins: [mixin] } </script> <style> </style>Student.vue
<template> <div> <h2>{{ msg }}</h2> <h1 @click="showName">学生名称:{{ name }}</h1> <h1>学生性别:{{ sex }}</h1> <h1>学生年龄:{{ age }}</h1> </div> </template> <script> import {mixin} from ../mixin export default { props: [name, sex, age], data() { return { msg: hello,world } }, mixins:[mixin] } </script> <style> </style>上述引用方式属于局部引用 ,下列配置属于全局引用 ,作用在main.js,全局混入会给vm下的所有vc添加响应的配置 。
main.js import Vue from "vue"; import App from "./App.vue"; Vue.config.productionTip = false; // 全局引用 import {mixin} from ./mixin Vue.mixin(mixin) new Vue({ render: (h) => h(App), }).$mount("#app");2.9 插件
功能:用于增强Vue
本质:包含install方法的一个对象 ,install的第一个参数是Vue ,第二个以后的参数是插件使用者传递的数据 。install(Vue,x,y,...) 与 main.js中先import导入 ,后Vue.use(plugins,1,2,...) 。plugins.js
export default { install(Vue) { // 定义全局过滤器 Vue.filter("mySlice", function (value) { return value.slice(0, 4); }); // 定义全局指令 Vue.directive("fbind", { // ... }); // 定义全局混入 Vue.mixin({ //... }); // 给Vue原型上添加一个hello方法(vm和vc就都能用了) Vue.prototype.hello = () => { alert("hello"); }; // 给Vue原型上添加一个属性(vm和vc就都能用了) Vue.prototype.x = 100 }, };main.js
import Vue from "vue"; import App from "./App.vue"; Vue.config.productionTip = false; // 全局引用插件 import plugins from ./plugins Vue.use(plugins) new Vue({ render: (h) => h(App), }).$mount("#app");2.10 scoped样式
作用:让样式在局部生效 ,防止冲突 。写法:
当前vue-cli创建Vue项目 ,webpack版本是4.xx.xx时 ,此时不能直接安装最新的less-loader版本 ,因为最新的less-loader是在webpack5的基础上适配的 ,应该安装less-loader 6~7之间的版本 。 // 两条语句学习一下 // 查看目前发布的版本 npm view xxxx versions // 安装指定版本的工具 npm install xxxx@版本号
三 、组件通信
3.1 父传子
父组件向子组件通信采用props属性 ,详解本文:2.7props配置 章节。
3.2 子传父
通过父组件给子组件传递函数类型的props实现:子向父传值 。App.vue
<template> <div> <School :getSchoolName="getSchoolName"></School> </div> </template> <script> import School from ./components/School.vue; export default { components: { School }, methods: { getSchoolName(name) { console.log(app接收到了, name); } // 接收多个参数 ,1 、可以用ES6的新语法,将其他的参数自动包装成一个params数组 2、对个参数包装成对象 getSchoolName(name,...params) { console.log(app接收到了, name,params); } } } </script>School.vue
<template> <div> <h1>学校名称:{{ name }}</h1> <h1>学校地址:{{ address }}</h1> <button @click ="sendSchoolName">点击创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!