1.监视属性
先推荐大家安装第一个vscode常用插件
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>天气案例_监视简写</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script>
</head><body><!-- 准备好一个容器 --><div id="root"><h2>今天天气很{{weather}}</h2><button @click="change">切换天气</button></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {isHot: true,},methods: {change() {this.isHot = !this.isHot;}},computed: {weather() {return this.isHot ? "炎热" : "寒冷"}},watch: {//当只有handler的时候才能使用简写形式// isHot: {// handler(newValue, oldValue) {// console.log("isHot被修改了", newValue, oldValue);// }// // deep:true,// // immediate: true//初始化时让handler调用一下// }//简写形式// isHot(newValue, oldValue) {// console.log("isHot被修改了", newValue, oldValue);// }}})//完整写法// vm.$watch('isHot', {// handler(newValue, oldValue) {// console.log("isHot被修改了", newValue, oldValue);// }// })//简写vm.$watch('isHot', function (newValue, oldValue) {console.log("isHot被修改了", newValue, oldValue);})</script></body></html>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>姓名案例_watch实现</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script><style>* {padding: 5px;margin: 5px;}</style>
</head>
<!-- computed和watch之间的区别:1.computed能完成的功能,watch都可以完成。2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。两个重要的小原则:1.所被vue管理的函数,最好写成普通函数,这样this的指向才是vm 或组件实例对象。2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、promise的回调函数 等),最好写成箭头函数,这样this的指向才是vm 或组件实例对象。--><body><!-- 准备好一个容器 --><div id="root"><!-- 以后注意在模板中 {{}} 中到底写的是 data中属性 还是 methods中的方法 还是 computed里的计算属性 嗯! --><div id="father" style="width: 300px;border: 2px red solid;margin:auto auto;"><span>姓:</span> <input type="text" style=" width: 100px; height: 15px;" v-model="name.lastName"><br><span>名:</span> <input type="text" style=" width: 100px; height: 15px;" v-model="name.firstName"><br><span>全名:</span><div style="display: inline-block;width: 150px;height: 15px;margin-left: 40px;"><span>{{fullName}}</span><br></div><br></div></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {name: {lastName: '',firstName: ''},fullName: ''},watch: {name: {deep: true,handler(n, o) {// vue管理函数 箭头函数 this==window 普通函数 vue代理 所以 this==vm// 而普通函数 在vue管理函数里执行 箭头函数用的就是 this外面的对象 所以this == vm,若是用普通函数 ,因为这个函数用了普通函数this// 传进来了。那么this 就是window调用的 this==window//如果写成普通函数 那么this 就是windowssetTimeout(function(){ //异步任务延迟 用 watchthis.fullName = this.name.lastName + '-' + this.name.firstName;}, 1000);//mssetTimeout(() => {//异步任务延迟 用 watchthis.fullName = this.name.lastName + '-' + this.name.firstName;}, 1000);//ms}}}})</script></body></html>
2.绑定样式
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>绑定样式</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script><style>/* 基础 */.basic {width: 400px;height: 100px;padding: 30px;border: 1px solid black;}/* 三选一 */.happy {background-color: red;}.sad {background-color: grey;}.normal {background-color: skyblue;}.j_aW{background-color: pink;}/* 三个能同时使用 */.atjmj1 {background-color: greenyellow;}.atjmj2 {font-size: 60sp;}.atjmj3 {border-radius: 30px;}</style>
</head>
<!-- 绑定样式:1.class样式写法 :class="xxx" xxx可以是字符串、对象、数组。字符串写法适用于:类名不确定,要动态获取。对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。2.style样式:style="{fontSize:xxx}" 其中xxx是动态值。:style="[a,b]" 其中a、b是样式对象。-->
<body><!-- 准备好一个容器 --><div id="root"><!-- 会把class 和 :class里面都汇总成最终一个 class了 --><!-- 绑定class样式 --字符串写法 适用于:样式的类名不确定,需要动态确定 --><div class="basic" :class="mood" id="demo" @click="changeMood">test</div><hr><!-- 绑定class样式 --数组写法 适用于:样式的个数不确定,名字也不确定--><div class="basic" :class="classArr">test</div><button @click="removeArrFirst">移掉数组第一个元素</button><br>请输入样式名 <input type="text" v-model="styleName"> <button @click="submit">点击提交</button><hr><!-- 绑定class样式 --对象写法,适用于:要绑定的样式个数确定 名字也确定,但要动态决定用不用 --><div class="basic" :class="classObj">test</div><hr><h1>内联样式</h1><!-- <div class="basic" :style="{fontSize: fsize+'px'}">test</div> --><div class="basic" :style="styleObj">test</div><!-- 绑定style 样式 --对象写法 --><hr><!-- 绑定style 样式 --数组写法 --><div class="basic" :style="[styleObj,styleObj2]">test</div></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {mood: 'happy',classArr: ['atjmj1', 'atjmj2', 'atjmj3'],styleName: '',classObj:{atjmj1:false,atjmj3:false,j_aW:true},fsize:40,styleObj:{fontSize: '40px',color:'red'},styleObj2:{backgroundColor:'orange'}},methods: {changeMood(event) {const classArr = ['happy', 'sad', 'normal']// document.getElementById('demo').className = 'basic sad';//这样也可以更改样式// event.target.className = 'basic sad';这样也行//[0,1)随机值let index = Math.floor(Math.random() * 3)//向下取整 [0,2]的整数this.mood = classArr[index]},removeArrFirst() {this.classArr.shift();},submit() {this.classArr.push(this.styleName);}},})</script></body></html>
3.条件渲染
1.v-show
v-show的底层实现就是 display:none ,不删除dom节点
2.v-if
直接把dom都干掉
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>条件渲染</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script>
</head><!-- 条件渲染:1.v-if写法:(1).v-if="表达式"(2).v-else-if="表达式"(3).v-else="表达式"适用于:切换频率较低的场景。特点:不展示的DOM元素直接被移除。注意:v-if可以和:vrelse-if、v-else一起使用,但要求结构不能被“打断”。2.v-show写法:v-show="表达式"适用于:切换频率较高的场景。特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
-->
<body><!-- 准备好一个容器 --><div id="root"><!-- 使用v-show做条件渲染 --><!-- <h2 v-show="isShow">欢迎来到{{name}}</h2> --><!-- <h2 v-show="1===1">欢迎来到{{name}}</h2> --><!-- 使用v-if做条件渲染 --><!-- <h2 v-if="isShow">欢迎来到{{name}}</h2> --><h2>当前的n值是{{n}}</h2><button @click="n++">点我n+1</button><div v-show="true"><ol><li v-show="n===1">Angular</li><li v-show="n===2">React</li><li v-show="n===3">Vue</li></ol><ol><li v-if="n===1">Angular</li><li v-if="n===2">React</li><li v-if="n===3">Vue</li></ol><!-- v-if v-else 和 v-else-if --><ul><li v-if="n===1">Angular</li><li v-else-if="n===2">React</li><li v-else>Vue</li></ul></div><!-- template不影响结构 就不用加div了 只能配合v-if --><template v-if="n===1"><h2>你好</h2><h2>尚硅谷</h2><h2>北京</h2></template></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {name: 'jmj',isShow: false,n: 0}})</script></body></html>
4.列表渲染
1.基本列表
<!DOCTYPE html>
<html lang="en"><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><!-- :key 让每一个li都有一个唯一的标识 --><!-- <li v-for="person in persons" :key="person.id">{{person.name}} - {{person.age}}</li> --><!-- <li v-for="(person,index) in persons" :key="person.id">{{index}} - {{person.name}} - {{person.age}}</li> --><!-- 把key设置为索引 --><!-- <li v-for="(person,index) in persons" :key="index">{{index}} - {{person.name}} - {{person.age}}</li> --><!-- of和in都行 --><li v-for="(person,index) of persons" :key="person.id">{{index}} - {{person.name}} - {{person.age}}</li><!-- 遍历对象 --><h2>人员列表 遍历对象 </h2><li v-for="(value,key) of car" :key="key">{{key}}={{value}}</li><h2>人员列表 遍历字符串(用得少) </h2><li v-for="(value,key) of str" :key="key">{{key}}={{value}}</li><h2>人员列表 遍历指定次数(用得少) </h2><li v-for="(num,index) of 5" ::key="index">{{index}}={{num}}</li></ul></div><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: 19},{id: '003',name: '王五',age: 20}],car: {name: '奥迪A8',price: '70万',color :'黑色'},str:'hello'}})</script></body></html>
2.key原理
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>key原理</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script>
</head>
<!-- 面试题:react、vue中的key有什么作用?(key的内部原理)1.虚拟DOM中key的作用:key是虚拟DoM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DoM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:2.对比规则:(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:@.若虚拟DOM中内容没变,直接使用之前的真实DOM!@.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。(2).旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到到页面。3.用index作为key可能会引发的问题:1.若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。2.如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。4.开发中如何选择key?:1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。-->
<body><!-- 准备好一个容器 --><div id="root"><!-- 遍历数组 --><div><button @click="add">添加一个老刘</button></div><h2>人员列表 遍历数组(用得最多)</h2><ul><li v-for="(person,index) of persons" :key="index">{{index}} - {{person.name}} - {{person.age}}<input type="text" :class="person.class" v-model:value="person.value"></li></ul></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {persons: [{id: '001',name: '张三',age: 18,class: "x",value: '张三'},{id: '002',name: '李四',age: 19,class: "x",value: '李四'},{id: '003',name: '王五',age: 20,class: "x",value: '王五'}]},methods: {add() {//虚拟dom好像不会对比样式 只要是同一个标签 值一样,就不会被替换const p = { id: '004', name: '老刘', age: 40, class: 'y', value: '老刘' };// this.persons[0].class='t';//往数组前方加东西this.persons.unshift(p);// this.persons.shift();//从前面删除}},})</script></body></html>
3.列表过滤
<!DOCTYPE html>
<html lang="en"><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" placeholder="请输入名字" v-model="searchObj.keywords"><ul><!-- <li v-for="(person,index) of persons" :key="person.id" v-show="person.name.includes(search)">{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}</li> --><li v-for="(person,index) of filterArr" :key="person.id">{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}</li></ul></div><!-- 推荐用计算属性实现 --><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {search: '',searchObj: {keywords: ''},persons: [{id: '001',name: '马冬梅',sex: '女',age: 23},{id: '002',name: '周杰伦',sex: '男',age: 19},{id: '003',name: '温兆伦',sex: '男',age: 18},{id: '004',name: '周冬雨',sex: '女',age: 20}]},computed: {filterArr() {//includes可以包含空字符串 indexOf包含空字符下标是0return this.persons.filter(p => p.name.includes(this.searchObj.keywords));}},})</script></body></html>
4.列表排序
<!DOCTYPE html>
<html lang="en"><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" placeholder="请输入名字" v-model="searchObj.keywords"><button @click="asc">年龄升序</button><button @click="desc">年龄降序</button><button @click="origin">原顺序</button><ul><!-- <li v-for="(person,index) of persons" :key="person.id" v-show="person.name.includes(search)">{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}</li> --><li v-for="(person,index) of filterArr" :key="person.id">{{index}} - {{person.name}} - {{person.age}} - {{person.sex}}</li></ul></div><!-- 推荐用计算属性实现 --><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el: "#root",data: {search: '',searchObj: {keywords: ''},soft:{asc:false,desc:false},persons: [{id: '001',name: '马冬梅',sex: '女',age: 23},{id: '002',name: '周杰伦',sex: '男',age: 19},{id: '003',name: '温兆伦',sex: '男',age: 18},{id: '004',name: '周冬雨',sex: '女',age: 20}]},computed: {filterArr() {//js里 0也可以是 false !0就是true//includes可以包含空字符串 indexOf包含空字符下标是0return this.persons.filter(p => p.name.includes(this.searchObj.keywords)).sort((a,b)=>{if(this.soft.asc){return a.age - b.age;}else if(this.soft.desc){return b.age - a.age;}else{return 0;}});}},methods: {asc(){this.soft.asc =true;this.soft.desc =false;},desc(){this.soft.asc =false;this.soft.desc =true;},origin(){this.soft.asc =false;this.soft.desc =false;}},})</script></body></html>
5.模拟数据检测
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>Document</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script>
</head><body><script type="text/javascript">let data = {name: '辽工',address: '北京',student:{name:'tom',age:18}}let vm={}//构造函数//创建一个监视的实例对象,用于监视data中属性的变化const obj = new Observer(data);vm._data =data = objconsole.log(vm);console.log(vm._data === data);//创建一个监视的实例对象function Observer(obj) {//汇总对象中所有的属性形成一个数组const keys = Object.keys(obj);// console.log(keys);//遍历keys.forEach((k) => {//this是实例对象Object.defineProperty(this, k, {get() {console.log(k+'被读取了');return obj[k];},set(val) {console.log(k+'被改变了,我要去解析模板,生成虚拟dom.. 我要开始忙了,改变的值为:'+val);obj[k] = val;}})})}//定时器// setInterval(()=>{// if(data.name!=='辽工'){// console.log('name被改变');// }// },1000)</script></body></html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script>
</head><!-- 数据劫持 数据代理 都离不开 Object.defindedProperty(target,key,{get(){},set(){}}) 这个方法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的根数据对象添加属性!!!通过代理的set添加的对象,以及其子对象都是响应式的,而数组比较特殊,对每一项不会做响应式,但是里面的对象以及子对象的属性都是响应式的,要想修改数组,就调用上面API,vue实现的动态代理,都可以帮你实现响应式
--><body><!-- 准备好一个容器 --><div id="root"><h1>学生信息</h1><button @click="student.age++">年龄添加一岁</button><button @click="fun1">添加性别属性,默认值:男</button><button @click="fun2">在列表首位添加一个朋友</button><button @click="fun3">修改第一个朋友的名字为:张三</button><button @click="fun4">添加一个爱好</button><button @click="fun5">修改第一个爱好为:开车</button><button @click="fun6">过滤掉爱好:抽烟</button><h3>姓名:{{student.name}}</h3><h3>年龄:{{student.age}}</h3><h3 v-if="student.sex">性别:{{student.sex}}</h3><h3>爱好:</h3><ul><li v-for="(h,index) in student.hobby" :key="index">{{h}}</li></ul><h3>朋友们:</h3><ul><li v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li></ul></div><script type="text/javascript" >Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示const vm = new Vue({el:"#root",data: {student:{name:'tom',age:18,hobby:['抽烟','喝酒','烫头'],friends:[{name:'jerry',age:35},{name:'tony',age:36}]}},methods: {fun1(){Vue.set(this.student,'sex','男');},fun2(){let friend = {name:'jack',age:37}console.log(friend);this.student.friends.unshift(friend);},fun3(){this.student.friends[0].name = '张三';},fun4(){this.student.hobby.push('乒乓球');},fun5(){// this.student.hobby.splice(0,1,'开车');// Vue.set(this.student.hobby,0,'开车')this.$set(this.student.hobby,0,'开车')},fun6(){this.student.hobby = this.student.hobby.filter((h)=>h!=='抽烟')//就算赋给普通集合,也会通过vm所劫持的set方法把普通集合里的所有对象都变成响应式的,}},}) </script></body>
</html>