十四天学会Vue——Vue核心(理论+实战)中篇(第二天)

声明:是接着上篇讲的哦,感兴趣可以去看一看~

  这里一些代码就不写了,为了缩减代码量,大家知道就可以了:  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

热身小tips,可以安装这个插件,这样写代码有提示哦~
在这里插入图片描述

一、Vue核心(中篇)

1.9 监视属性(侦听属性)

使用计算属性确定天气案例

<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">	const vm = new Vue({el:'#root',data:{isHot:true,},computed:{info(){return this.isHot ? '炎热' : '凉爽'}},methods: {changeWeather(){this.isHot = !this.isHot}},})</script>  

所有vue写成的函数都要写成普通函数,不要使用箭头函数,因为箭头函数牵涉到没有this的问题

监视属性watch:

		<!-- 准备好一个容器--><div id="root"><h2>今天天气很{{info}}</h2><button @click="changeWeather">切换天气</button></div></body><script type="text/javascript">	const vm = new Vue({el:'#root',data:{
2.监视的属性必须存在,才能进行监视!!isHot:true,},computed:{info(){return this.isHot ? '炎热' : '凉爽'}},methods: {changeWeather(){
1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作this.isHot = !this.isHot}},
3.监视的两种写法:(1).new Vue时传入watch配置(2).通过vm.$watch监视/* watch:{isHot:{immediate:true, //初始化时让handler调用一下//handler什么时候调用?当isHot发生改变时。handler(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue)}}} */})vm.$watch('isHot',{immediate:true, //初始化时让handler调用一下//handler什么时候调用?当isHot发生改变时。handler(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue)}})</script>

深度监视

	<!-- 深度监视:(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><button @click="numbers.a++">点我让a+1</button><h3>b的值是:{{numbers.b}}</h3><button @click="numbers.b++">点我让b+1</button><button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>{{numbers.c.d.e}}</div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。const vm = new Vue({el:'#root',data:{isHot:true,numbers:{a:1,b:1,c:{d:{e:100}}}},computed:{info(){return this.isHot ? '炎热' : '凉爽'}},methods: {changeWeather(){this.isHot = !this.isHot}},watch:{isHot:{// immediate:true, //初始化时让handler调用一下//handler什么时候调用?当isHot发生改变时。handler(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue)}},//监视多级结构中某个属性的变化/* 'numbers.a':{handler(){console.log('a被改变了')}} *///监视多级结构中所有属性的变化numbers:{deep:true,handler(){console.log('numbers改变了')}}}})</script>

监视属性的简写

 <div id="root"><h2>今天天气很{{info}}</h2><button @click="changeweather">切换天气</button></div><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: {// isHot: {  //对象//     // immediate: true,//     // deep: true,  //深度监视//     handler (newValue, oldValue) {//         console.log('info被修改了', newValue, oldValue)//     }// }// 只有handler配置项可以简写  ()就代表handler函数isHot (newValue, oldValue) {console.log('info被修改了', newValue, oldValue)}}})// vm.$watch('isHot', {//     handler (newValue, oldValue) {//         console.log('info被修改了', newValue, oldValue)//     }// })vm.$watch('isHot', function (newValue, oldValue) {console.log('isHot被修改了', newValue, oldValue)})//简写/* vm.$watch('isHot',(newValue,oldValue)=>{console.log('isHot被修改了',newValue,oldValue,this)}) */</script>

天气案例中计算属性和侦听属性区分:

<!-- 准备好一个容器--><div id="root">姓:<input type="text" v-model="firstName"> <br/><br/>名:<input type="text" v-model="lastName"> <br/><br/>全名:<span>{{fullName}}</span> <br/><br/></div></body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。const vm = new Vue({el:'#root',data:{firstName:'张',lastName:'三',fullName:'张-三'},watch:{firstName(val){setTimeout(()=>{console.log(this)this.fullName = val + '-' + this.lastName},1000);},lastName(val){this.fullName = this.firstName + '-' + val}}})</script>

1.10 绑定样式

 <style>.basic {width: 400px;height: 100px;border: 1px solid black;}.happy {border: 4px solid red;;background-color: rgba(255, 255, 0, 0.644);background: linear-gradient(30deg, yellow, pink, orange, yellow);}.sad {border: 4px dashed rgb(2, 197, 2);background-color: gray;}.normal {background-color: skyblue;}.atguigu1 {background-color: yellowgreen;}.atguigu2 {font-size: 30px;text-shadow: 2px 2px 10px red;}.atguigu3 {border-radius: 20px;}</style><script type="text/javascript" src="../../js/vue.js"></script>
</head><body><!-- 绑定样式:1. class样式写法:class="xxx" xxx可以是字符串、对象、数组。字符串写法适用于:类名不确定,要动态获取。对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。2. style样式:style="{fontSize: xxx}"其中xxx是动态值。:style="[a,b]"其中a、b是样式对象。--><!-- 准备好一个容器--><div id="root"><!-- 绑定class样式  字符串写法   适用于:样式的类名不确定 需要动态指定 --><div class="basic" :class='mood' @click="changeMood">{{name}}</div><br><br><!-- 绑定class样式  数组写法  适用于 帮绑定的样式个数不确定 名字也不确定 --><!-- 相当于拿到的是值 --><div class="basic" :class="['atguigu1', 'atguigu2' , 'atguigu3' ]" @click="changeMood">{{name}}</div><br><br><!-- 相当于拿到的是变量 还要从vm中找 --><!-- <div class="basic" :class="[a, b , c]" @click="changeMood">{{name}}</div><br><br> --><div class="basic" :class="classArr" @click="changeMood">{{name}}</div><br><br><!-- 对象写法   要绑定的样式个数确定、名字也确定,但要动态决定用不用--><!-- <div class="basic" :class="classObj" @click="changeMood">{{name}}</div><br><br> --><!-- 没在vm上定义 在vue开发工具添加样式不可能实现 --><div class="basic" :class="{ atguigu1: false,atguigu2: false}" @click="changeMood">{{name}}</div><br><br><!-- 绑定style样式 对象写法 适用于:要绑定的样式个数确定、名字也确定 但要动态决定用不用 --><!-- <div class="basic" :style="{fontSize:fsize + 'px'}">{{name}}</div><br><br> --><!-- <div class="basic" :style="styleObj">{{name}}</div><br><br> --><!-- <div class="basic" :style="[styleObj1,styleObj2]">{{name}}</div><br><br> --><!-- 绑定style样式 数组写法 适用于:要绑定的样式个数确定、名字也确定 但要动态决定用不用 --><div class="basic" :style="styleArr">{{name}}</div><br><br></div>
</body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el: '#root',data: {name: '尚硅谷',mood: 'normal',classArr: ['atguigu1', 'atguigu2', 'atguigu3'],// a: 'atguigu1',// b: 'atguigu2',// c: 'atguigu3',classObj: {atguigu1: false,atguigu2: false},// fsize: 40// styleObj1: {//     fontSize: '60px',//     color: 'red',// }, styleObj2: {//     backgroundColor: 'orange'// }, styleArr: [{fontSize: '60px',color: 'red',}, {backgroundColor: 'orange'}]}, methods: {changeMood () {// // 如果这样写 直接js了 不用vue// // document.querySelector('.basic').className = 'basic happy'// this.mood = 'happy'const arr = ['happy', 'sad', 'normal']const index = Math.floor(Math.random() * 3)this.mood = arr[index]}},})
</script>

1.11 条件渲染

条件渲染:
1.v-if
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

						2.v-show写法:v-show="表达式"适用于:切换频率较高的场景。特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
  <div id="root"><h2>当前的值是{{n}}</h2><button @click="n++">点我n+1</button><!-- <h2 v-show='a'>欢迎来到{{name}}</h2><h2 v-show="1===3">欢迎来到{{name}}</h2>  --><!-- 用v_if做条件渲染  结构也不显示 --><!-- <h2 v-if='false'>欢迎来到{{name}}</h2> --><!-- 切换频率 如果成立 其他不成立--><!-- 快  高效 --><!-- <div v-show="n===1">a</div><div v-show="n===2">b</div><div v-show="n===3">c</div><div v-show="n===4">d</div> --><!-- 慢 低效 --><!-- <div v-show="n===1">a</div><div v-show="n===2">b</div><div v-show="n===3">c</div><div v-show="n===4">d</div> --><!-- 第一句找到了 后面就都不执行了  佐证    --><div v-if="n===1">a</div><div v-else-if="n===1">aa</div><div>@</div>//中间不能断<div v-else-if="n===3">c</div><div v-else>哈哈哈</div><!-- 就是不会破坏结果 可以直接拿到css样式 --><template v-if="n===1"><h2>1</h2><h2>3</h2><h2>4</h2></template></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el: '#root',data: {name: '哈哈哈',a: false,n: 0},methods: {}});</script>
</body>

1.12 列表的渲染

1.基本列表

1.遍历数组数据形成页面上的列表

思路:使用v-for遍历数组对象,然后展示在列表上
具体说来就是:js中有顺序 要用数组对象
先写一个 想生成多个li 就在谁身上写个v-for 遍历
v-for能遍历,加在谁身上 谁就能遍历,persons能决定遍历多少次

<div id="root"><!-- 第一种写法:只有一个参数   遍历出来的是数组对象中的每一项 --><!-- 每一个li都有一个标识   (通过遍历)  所以有key -->//这里in也可以用of<li v-for="p in persons" :key="p.id">//使用插值语法中的p可能来自三个地方:data中的属性 计算属性 还有参数,这里是参数{{p.name}}-{{p.age}}</li><!-- 第二种写法:两个参数  分别是数组对象中的每一项  索引号 --><!-- <li v-for="(p,index) in persons" :key="p.id"> --><!-- key的取值 只要保证每一项对应的key值不一样即可 --><li v-for="(p,index) in persons" :key="index"><!-- {{p.name}}-{{p.age}} -->{{p}}---{{index}}</li></div><script type="text/javascript">new Vue({el: '#root',data: {persons: [{ id: '001', name: '张三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 }]}});</script>

2.遍历对象数据形成页面上的列表

<!-- 遍历对象 --><li v-for="(value,key) of car" :key="key"><!-- {{p.name}}-{{p.age}} -->{{key}}:{{value}}</li>car: {name: '奥利',price: '70万',color: '黑色'}

具体来说一共五种

<body><div id="root"><!-- 1.遍历数组 --><!-- 第一种写法:只有一个参数   遍历出来的是数组对象中的每一项 --><!-- 每一个li都有一个标识   (通过遍历)  所以有key --><li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}}</li><!-- 第二种写法:两个参数  分别是数组对象中的每一项  索引号 --><!-- <li v-for="(p,index) in persons" :key="p.id"> --><!-- key的取值 只要保证每一项对应的key值不一样即可 --><li v-for="(p,index) in persons" :key="index"><!-- {{p.name}}-{{p.age}} -->{{p}}---{{index}}</li><!-- 2.遍历对象 --><li v-for="(value,key) of car" :key="key">{{key}}:{{value}}</li><!-- 3.遍历字符串 --><li v-for="(index,char) of str" :key="index">{{index}}:{{char}}</li><!-- 4.遍历指定次数 --><li v-for="(number,index) of 6" :key="index">{{index}}:{{number}}</li></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el: '#root',data: {persons: [{ id: '001', name: '张三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 }],car: {name: '奥利',price: '70万',color: '黑色'},str: 'hello'}});</script>

2.key的原理

1.按照数组 key作用:给节点进行标识
2.效率 每一个人后面加input框 p.id唯一数据标识

死记硬背:遍历列表的时候就是会有个key来标识每个节点,使用key来标识;这里如果牵涉到列表的增加或者删除,使用id来标识,如果不牵涉则使用index,如果没有写index,vue默认使用index来标识
在这里插入图片描述

上述图片的详细理解:

1.拿到刚开始的数据,也就是还没有添加老刘
2.vue会将初始数据生成虚拟DOM,(加了key) 此时页面中没有数据,内存中有
3.vue将虚拟DOM转化为真实DOM,真实DOM才是用户能看到的,用户才可以在input框输入
4.添加老刘,更新数据,生成了新的数据
5.vue根据新数据生成虚拟DOM
6.因为是第一条的添加位置,所以老刘的key对应为0
7.vue会开启虚拟DOM对比算法 也就是新旧虚拟DOM对比
8.按照顺序,从key为0开始对比,这里的老刘-30属于文本节点,input框属于标签节点。key=0时,文本节点不同,则老刘-30生成新的数据,从虚拟DOM转化为真是DOM;标签节点相同(,这里只看虚拟DOM,单纯诸葛词语对比,因为值对比虚拟DOM,不要看真实DOM),实现复用。也就是旧的虚拟DOMinput框一定转化为真实的DOM,所以这里会拿之前变好的input真实DOM框,实现复用。
9.挨个对比,相同的直接用之前的,不同的直接下来(直接生成真实DOM)
10.这里到了王2-50 key=3,找不到与他相同的 所以新的虚拟DOM直接转化为真实的DOM,那么真实DOM的input框下来的时候,用户还没有填数据,就为空

从这里就可以看出:效率低(因为错乱的数据都不能使用,统统都需要vue工作由虚拟DOM转化为真实DOM,都是需要重新生成,错误DOM更新) 并且数据错乱

另外:如果将王五追加在后面没有问题,但是对数据破坏顺序的操作,就不能使用index。而需要使用数据唯一标识id

另外 不写key的值 index在遍历的时候vue会自动补充,index会取遍历时的索引值 往后加push 好用

手机、邮箱、用户,vue不可能采集到这些信息,所以只能通过数据库录入的方式 id:001

有上述可知,再把列表项追加到第一位时要用标识: p.id 如下图 想改成index 直接在下面改即可

<body><div id="root"><!-- 1.在persons的上方追加老刘  绑定click事件并且只添加一次--><h2>人员列表</h2><button @click.once="add">添加一个老刘</button><!-- //发现html结构中没有key  因为他是在vue内部使用  转化为真实的dom之后就丢弃了     --><li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}}<input type="text"><!-- //2. 这里加上input框  是为了实现在每一个对象后都有一个对应的input框 // 会发现当我们填写之后添加老刘,就会出现错乱的情况  不仅仅是效率低下的问题  //  此时使用p.id(数据的唯一标识)不会有问题   这里就开始引入key工作原理和虚拟dom对比算法--></li></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el: '#root',data: {persons: [{ id: '001', name: '张三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 }]}, methods: {add () {const p = { id: '004', name: '老刘', age: 40 }this.persons.unshift(p)}}});</script>

3.列表过滤

<body><div id="root"><input type="text" placeholder="请输入名字" v-model="keyword"><ul><li v-for="p in filterPersons">{{p.name}}-{{p.age}}</li></ul></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示new Vue({el: '#root',data: {persons: [{ id: '001', name: '张三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 }],keyword: '',// filterPersons: []},// watch: {//     keyword: {//         immediate: true,//一上来就调用 用户什么也没输入的情况下  这样可以获得完整的数据//         // 死记硬背:通过watch监听 能够知道keyword被修改了//         // console.log('keyword被修改了', val)//         // 这里的p与上文li中的p不是一个变量  只不过名字相同   根据filter语法  p标识数组对象中的每一个对象//         // 但是这里有一个问题:就是filter返回的新数组给了persons  这导致persons数据缺失  所以需要新的空数组接收//         // this.persons = this.persons.filter((p) => {//         //     return p.name.indexOf(val) !== -1//         // })//         // 每次都从persons过滤数据可以避免  但是这里有一个问题  在没有过滤的情况下不展示所有数据  解决办法:                immediate: true//         handler (val) {//             this.filterPersons = this.persons.filter((p) => {//                 return p.name.indexOf(val) !== -1//             })//         }//     }// }// computed返回值就是返回真正的过滤结果  filterPersons  依赖keyword发生变化  computed的返回值就是结果computed: {filterPersons () {return this.persons.filter((p) => {return p.name.indexOf(this.keyword) !== -1})}}});</script>

4.列表排序

思路如下图:
思路
在这里插入图片描述

    <div id="root"><input type="text" placeholder="请输入名字" v-model="keyword"><!-- //1.不同按钮 用不同序号标识 然后根据不同的sortType值知道选的哪个button --><button @click="sortType = 2">年龄升序</button><button @click="sortType = 1">年龄降序</button><button @click="sortType = 0">原顺序</button><ul><li v-for="p in filterPersons">{{p.name}}-{{p.age}}</li></ul></div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示new Vue({el: '#root',data: {sortType: 0, // 0,1,2分别是原顺序  年龄降序 年龄升序persons: [{ id: '001', name: '张三', age: 18 },{ id: '002', name: '李四', age: 44 },{ id: '003', name: '王五', age: 20 },{ id: '004', name: '赵四', age: 22 },],keyword: '',},// computed返回值就是返回真正的过滤结果  filterPersons  依赖keyword发生变化  computed的返回值就是结果computed: {filterPersons () {// 2.需要明确:过滤+排序都是在filterPersons基础之上进行的const arr = this.persons.filter((p) => {return p.name.indexOf(this.keyword) !== -1})//if 语句中使用一个数值时,该数值会被隐式地转换为布尔值//这一次提到sortType是为了判断是不是为0  布尔值中零代表false  非零值代表trueif (this.sortType) {arr.sort((p1, p2) => {//这一次提到sortType是为了判断是不是为1return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age})}return arr}}});</script>

这里分不清是升序还是降序可以直接试一下 不是升序就是降序

let arr = [1, 6, 8, 43, 44];  
arr.sort(function (a, b) {  return a - b; // 升序排序  
});  
console.log(arr)

5.更新时的一个问题

会出现修改数据不奏效的问题,这是因为直接拿到数组的索引值来改变数据是不能奏效的,Vue内部不答应,我们可以用splice语句一集下问题道德Vue.set语句 ,下面6,7,8,9都会一直在探讨这个问题

<!-- 准备好一个容器--><div id="root"><h2>人员列表</h2><button @click="updateMei">更新马冬梅的信息</button><ul><li v-for="(p,index) of persons" :key="p.id">{{p.name}}-{{p.age}}-{{p.sex}}</li></ul></div><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'马冬梅',age:30,sex:'女'},{id:'002',name:'周冬雨',age:31,sex:'女'},{id:'003',name:'周杰伦',age:18,sex:'男'},{id:'004',name:'温兆伦',age:19,sex:'男'}]},methods: {updateMei(){// this.persons[0].name = '马老师' //奏效// this.persons[0].age = 50 //奏效// this.persons[0].sex = '男' //奏效// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})}}}) </script>

6.Vue监测数据改变的原理_对象

先探讨Vue检测对象的数据改变,再检测数组数据的改变
首先我们知道data数据中的属性最终会放在vm中,但是data数据到vm数据需要经历两步:

Vue中实现数据监视:

1.加工data
2.vm._data=data
在这里插入图片描述
reactive代表响应式 是数据改变页面也会改变

7.模拟一个数据监测

步骤一:大家可能会想既然只要检测到data中数据的改变页面也会改变,并且控制条也要输出,那我只要自己写不就可以了吗?

 <script>let data = {name: '哈哈哈',address: '河南'}// 如果不写定时器 没办法实时检测数据的改变  所以采用定时器进行数据的实时监测// 并且需要引入变量tmp 这样做是为了让name值最后恢复与temp相同的值 省的代码一直被检测到发生变化,也就是让他们每次都保证相同 只进行数值发生改变的时候才会有变化let tmp = '哈哈哈'setInterval(() => {if (data.name !== '哈哈哈') {console.log('name被修改了', name)}}, 100)</script>

缺点:我们总不能每次数据改变就去开定时器吧,所以监测数据还是采用getter和setter
步骤二:我们试试使用Object.defineProperty匹配getter和setter

    <script>let data = {name: '哈哈哈'}Object.defineProperty(data, 'name', {get () {return data.name},set (val) {data.name = valconsole.log('name被修改')}})</script>

结果表示内存溢出:
在这里插入图片描述
原理:重复调用 不会停
在这里插入图片描述

使用Obverser方法检测数据属性的变化

<script>let data = {name: '哈哈哈',address: '河南'}const obs = new Observer(data)// 准备一个实例let vm = {}//将我们写出来的obs给data和vm._datavm._data = data = obs//创建一个监视的实例对象 用于监视data中的属性的变化function Observer (obj) {//汇总对象中所有的属性形成一个数组const keys = Object.keys(obj)//遍历keys.forEach((k) => {Object.defineProperty(this, k, {get () {//obj[k] 则是使用方括号语法来访问或设置 obj 对象上对应名称的属性。这是正确的做法,//因为它允许使用变量来动态地引用对象的属性return obj[k]}, set (val) {console.log(`${k}被改变了,我要去解析模版,生成虚拟dom,。。。我要开始忙了`)obj[k] = val}})})}</script>

在这里插入图片描述
缺点1:改变属性的时候必须全称 并且我们改变属性值之后会立刻显示在页面上
在这里插入图片描述
在这里插入图片描述
缺点2:对象中还有对象 多层 使用Observer只能监测一层对象属性,对象中如果嵌套对象,则不能检测;而Vue监测则是多层监测,直到找到不是对象的才罢休

模拟的数据监测:

在这里插入图片描述

Vue监测的数据:

在这里插入图片描述
所以引出了大牛还得数Vue监测数据的改变 ;只要改变属性 就能调用setter接着解析模版
在这里插入图片描述

8.Vue.set()方法

步骤一:要求学生添加性别,属于动态添加,譬如:用户点击了才会添加性别,所以我们不能直接添加:这里有一些问题需要理解:如果我们定义在student下的性别,在模版中写出可以在页面展示出来;如果没有在data中定义,写student.sex不会报错,因为只是未定义,undefined不会报错;但如果只是写sex就会报错

 <div id="root"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2><hr><h2>姓名:{{student.name}}</h2><!-- <h2>性别:{{student.sex}}</h2> --><!-- <h2>性别:{{sex}}</h2> --><!-- //不会报错 --><h2>性别:{{undefined}}</h2><h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2><ul><!-- 参数 如果有两个参数 那么用小括号  并且因为只是将数组元素展示在页面上 不涉及元素的添加和删除 直接index --><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: {name: '哈哈哈',address: '南京',student: {age: {rAge: 19,sAge: 29},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],// sex: '男'}}});</script>

步骤二:如果在控制台动态添加性别,会发现不会展示在页面上 后添加的不会有对应的getterhesetter 也就是不存在响应式
在这里插入图片描述

<div id="root"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2><hr><h2>姓名:{{student.name}}</h2><h2>性别:{{student.sex}}</h2><h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2><ul><!-- 参数 如果有两个参数 那么用小括号  并且因为只是将数组元素展示在页面上 不涉及元素的添加和删除 直接index --><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: {name: '哈哈哈',address: '南京',student: {name: 'tom',age: {rAge: 19,sAge: 29},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],// sex: '男'}}});</script>

所以根据Vue内部特性 也就是需要想用什么事先添加好 想要做到动态添加特性 需要是Vue.set()
步骤三:首先控制台打印:
两种添加响应式属性的方法:
第一种:Vue调用的API:Vue.set()
第一个参数表示往谁身上追加属性;第二个是追加的属性 第三是追加的属性值
在这里插入图片描述
在这里插入图片描述
第二种:vm.$set()
在这里插入图片描述

使用数据代理的方法知道:通过Object.defineProperty()原本是修改data上的属性转化为修改vm上的属性

在这里插入图片描述
使用button按钮添加

 <div id="root"><h2>学校名称:{{school.name}}</h2><h2>学校地址:{{school.address}}</h2><h2>学校校长:{{school.leader}}</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><ul><!-- 参数 如果有两个参数 那么用小括号  并且因为只是将数组元素展示在页面上 不涉及元素的添加和删除 直接index --><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: {school: {name: '哈哈哈',address: '南京',},student: {name: 'tom',age: {rAge: 19,sAge: 29},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],// sex: '男'}}, methods: {addSex () {Vue.set(this.student, 'sex', '女')}}});</script>

有局限:
必须在data中某一个对象中添加属性 不能直接在data下追加属性
在这里插入图片描述

9.Vue监测数据的改变_数组

Vue内部没有为数组匹配对应的getter和setter
在这里插入图片描述
Vue中使用push通过包装的思想,也就是Vue中使用的push,不是数组上原型对象上的push,而是Vue的push会经过两步:
1.调用原型对象上的push,2.重新模版解析,然后数组更新检测,对数据进行增删改查
并且返回的是真实能够影响到数组的,例如:filter 不能影响到数组 没有返回值

 <div id="root"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2><h1>爱好</h1><ul><li v-for="(h,index) in student.hobby" :key="index">{{h}}</li></ul><h1>朋友们</h1><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: {name: '哈哈哈',address: '南京',student: {name: 'tom',age: {rAge: 19,sAge: 29},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],hobby: ['抽烟', '喝酒', '烫头']}}});</script>

在这里插入图片描述
在这里插入图片描述
在Vue修改数组中的某个元素一定要用如下方法:

  					1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()2.Vue.set() 或 vm.$set(),

理论来源
在这里插入图片描述
所以更新时的问题,修改数据的解决办法是:不能使用数组元素的修改方法 而应该通过包装了的vue语句
在这里插入图片描述
使用Vue.set() vm.$set()来实现替换 也是响应式 但是用得不多
在这里插入图片描述

10 总结Vue数据检测

    <div id="root"><h1>学生信息</h1><h3>姓名:{{student.name}}</h3><h3>年龄:{{student.age}}</h3><!-- 2.当时没有的 添加一个性别 没有性别不要再出现 --><h3 v-if="student.sex">性别:{{student.sex}}</h3><!-- 1.逻辑简单 直接加加 --><button @click="student.age++">年龄一点一加</button><br><br><!-- 2.当时没有的 添加一个性别 没有性别不要再出现 --><button @click="addSex">添加性别属性,默认值:男</button><br><br><!-- 3.修改性别 里面是正常的js表达式 由于逻辑简单 直接写 --><button @click="student.sex='未知'">修改性别</button><br><br><!-- 4.使用unshift列表数组元素首位添加属性  对象里的属性是响应式的 --><button @click="addFriend">在列表首位添加元素</button><br><br><!-- 5.修改第一个朋友的名字为张三--><button @click="updateFirends">修改第一个朋友的名字为张三</button><br><br><!-- 6.添加爱好 --><button @click="addHobby">添加爱好</button><br><br><!-- 7.修改爱好 --><button @click="updateHobby">修改第一个爱好为:开车</button><br><br><!-- 8.Vue检测不到filter的新数组变化 因为不会返回新数组,我们自己把原来的数组替换  过滤掉爱好中的抽烟 --><button @click="removeSmoke">过滤掉爱好中的抽烟</button><h3>爱好</h3><ul><li v-for="(h,index) in student.hobby" :key="index">{{h}}</li></ul><h1>朋友们</h1><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: 29,friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],hobby: ['抽烟', '喝酒', '烫头']}}, methods: {addSex () {// this.student.sex = '男'// 一开始没有 后来有的vm.$set(this.student, 'sex', '男')}, addFriend () {this.student.friends.unshift({ name: 'amy', age: 23 })}, updateFirends () {//可是直接按照数组的形式来写  因为是对象数组索引值赋值修改,Vue不承认,没有对应的egetter和setter;//但是对象中有属性就会有getter和setter this.student.friends[0].name = '张三'}, addHobby () {this.student.hobby.push('学习')}, updateHobby () {//不能直接通过数组索引值修改// this.student.hobby.splice(0, 1, '开车')Vue.set(this.student.hobby, 0, '开车')}, removeSmoke () {this.student.hobby = this.student.hobby.filter((h) => {return h !== '抽烟'})}}});</script>

数据劫持:有人修改了student,对应的setterr会被调用(感知),然后模版解析
总结:

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的根数据对象 添加属性!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/16908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里通义千问大模型AI接入火车头自动生成内容插件

插件特点&#xff1a; 可以根据采集的关键词&#xff0c;自动生成文章可自定义提示词 也可以分析标题重写一个标题2个提问标签 如有需要可自由增加对话标签自己可以设置TXT关键词导入&#xff0c;自动采集生成 安装说明&#xff1a; 1.需要python环境 &#xff0c;具体可以…

新楚文化知网收录文学艺术类期刊投稿

《新楚文化》是由国家新闻出版总署批准&#xff0c;湖北省文学艺术界联合会主管&#xff0c;湖北今古传奇传媒集团有限公司主办的正规期刊。主要刊登文化、文学、艺术类稿件&#xff1b;包括传统文化、非遗、历史文化、地方文化、中外友好文化交流、文学作品研究、艺术研究等方…

在C++中自定义命名空间,在命名空间中定义string变量,同时定义一个函数实现单词逆置

代码 #include <iostream> #include <cstring> using namespace std; namespace my_space {string s;void reverse(string s);//定义逆置函数 } using namespace my_space; void my_space::reverse(string s){int lens.size();int i0;int jlen-1;while(i<j){//…

恶意退市潮?

一张A4纸&#xff0c;炸出一池鱼。史上&#xff08;最&#xff09;严新规&#xff0c;这一拳打到了&#xff08;违规减持&#xff09;上。 新规算是对新国九条的补充&#xff0c;更是给大股东们上紧箍咒。那市场买账吗&#xff1f;昨晚爆出19家董监高亲属&#xff08;违规&…

wireshark抓包,丢包分析?

前言 我们都知道&#xff0c;一般流量分析设备都支持pcap回放离线分析的功能&#xff0c;但如果抓的pcap丢了包&#xff0c;会影响最终安全测试的效果。比如说竞测现场需要提供pcap包测试恶意文件的检测功能&#xff0c;如果pcap中丢包&#xff0c;可能会导致文件还原失败&…

高稳定数显芯片防干扰抗噪数码屏驱动高亮LED驱动IC-VK16K33A/AA 最大13×3的按键扫描

产品型号&#xff1a;VK16K33A/AA 产品品牌&#xff1a;永嘉微电/VINKA 封装形式&#xff1a;SOP28/SSOP28 原厂&#xff0c;工程服务&#xff0c;技术支持&#xff01; 概述 VK16K33A/AA是一种带按键扫描接口的数码管或点阵LED驱动控制专用芯片&#xff0c;内部集成有数据…

2024系统架构师软考考题考点回忆版

2024年5月25日系统架构师软考试题/考点梳理 选择题 (75道单选题) 软件测试(P205) 静态测试:是被测程序不运行,只依靠分析和检查源程序的语句、结构、过程来检查程序是否有错误。动态测试:运行被测试程序,对得到的结果与预期的结果进行比较分析,同时分析运行效率和健壮…

RK3568笔记二十七:LPRNet车牌识别

若该文为原创文章&#xff0c;转载请注明原文出处。 记录自训练并在RK3568上部署。 一、介绍 LPRNet的Pytorch实现&#xff0c;一种高性能和轻量级的车牌识别框架。完全适用于中国车牌识别&#xff08;Chinese License Plate Recognition&#xff09;及国外车牌识别&#xf…

张大哥笔记:赚钱高手养成计划---如何将一份时间产生N份收入?

我们常说的赚钱的四种境界有哪些&#xff1f; 1.靠体力挣钱 2.靠技能挣钱 3.靠知识挣钱 4.靠平台钱生钱 所以对应的收入的模式就会是下面4种模式&#xff1a; 1.一份时间卖1次 2.一份时间卖N次 3.一份时间溢价卖N次 4.购买他人时间为自己所用 时间对于每个人都是相同的…

书生·浦语大模型全链路开源体系-作业1

视频链接&#xff1a;书生浦语大模型全链路开源体系_哔哩哔哩_bilibili 1. LLM发展 LLM是近年来人工智能领域的一个重要发展方向。大型语言模型的历史可以追溯到2017年,当时OpenAI推出了GPT-1(Generative Pre-trained Transformer)模型,这是一个基于Transformer架构的语言生成…

使用OpenVINO™.CSharp.API.Extensions.PaddleOCR NuGet Package快速实现OCR文本识别

PP-OCR是PaddleOCR自研的实用的超轻量OCR系统&#xff0c;可以实现端到端的图像文本检测。为了在C#平台实现使用OpenVINO™部署PP-OCR模型实现文本识别&#xff0c;让更多开发者快速上手PP-OCR项目&#xff0c;基于此&#xff0c;封装了OpenVINO.CSharp.API.Extensions.PaddleO…

【C语言】数据指针地址的取值、赋值、自增操作避坑

【C语言】数据指针的取值、赋值、自增操作避坑 文章目录 指针地址指针自增指针取值、赋值附录&#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Packed-ASCII字符串 大小端转换什么是大端和小端数据传输中的大小端总结大小端转换函数 指针地址 请看下列代码&#…

嵩山为什么称为五岳之尊

在此之前&#xff0c;人们心目中的五岳之尊一般是东岳泰山。自此以后&#xff0c;观点一定会改变&#xff1a;五岳之尊是中岳嵩山&#xff01;且听我慢慢道来。 首先将二者进行一下对比—— 中与东的对比&#xff0c;嵩山居中&#xff0c;泰山居东。东方是太阳升起的地方&#…

谷粒商城实战(029 业务-订单支付模块-支付宝支付2)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第305p-第p310的内容 代码编写 前端代码 这里使用的是jsp 在这里引用之前配置的各种支付信息 在AlipayConfig.java里 这里是调用阿里巴巴写…

AI大模型日报#0527:豆包大模型披露评测成绩、天工AI日活超100万、AI初创集体跳槽OpenAI

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-Large&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xf…

PyQt5-新手避坑指南(持续更新)

文章目录 一&#xff0e;前言二&#xff0e;开发环境三&#xff0e;坑1.程序没有详细报错就退出了2.qrc资源文件的使用3.QLabel文字自动换行4.图片自适应大小5.checkbox自定义样式后✓不见了6.多线程 四&#xff0e;记录 一&#xff0e;前言 本篇博客整理了一些初学者容易犯的…

技术贴 | Query 物理计划构建指南

在往期博客《执行器 - Query 执行详解》中&#xff0c;我们介绍到到一条 Query 的 SQL 语句需要经过&#xff1a;词法分析 —— 生成 AST 语法树 —— 生成物理计划。本期博客我们接续上篇讲解一条 Query 语句物理计划的具体结构&#xff0c;以及如何构建物理计划。 物理计划是…

Jmeter环境安装(超级简单)

Jmeter的安装是非常简单的&#xff0c;只需要将下载的安装包解压后&#xff0c;就可以运行了&#xff01;&#xff01; 一、首先要下载Jmeter 1.1、官网下载&#xff1a; 下载最新版&#xff1a;https://jmeter.apache.org/download_jmeter.cgi https://jmeter.apache.org/…

论文阅读》学习了解自己:一个粗略到精细的个性化对话生成的人物感知训练框架 AAAI 2023

《论文阅读》学习了解自己&#xff1a;一个粗略到精细的个性化对话生成的人物感知训练框架 AAAI 2023 前言 简介研究现状任务定义模型架构Learning to know myselfLearning to avoid Misidentification损失函数实验结果消融实验 前言 亲身阅读感受分享&#xff0c;细节画图解释…

代码随想录算法训练营第四十一天 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

理论基础 代码随想录 视频&#xff1a;从此再也不怕动态规划了&#xff0c;动态规划解题方法论大曝光 &#xff01;| 理论基础 |力扣刷题总结| 动态规划入门_哔哩哔哩_bilibili 动归五部曲 1.dp数组以及下标的含义 2.递推公式 3.dp数组如何初始化 4.遍历顺序(例如先背包再…