十四天学会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.rhkb.cn/news/333890.html

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

相关文章

【LeetCode】【9】回文数(1047字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示进阶Python实现 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给一个整数x&#xff0c;如果x是一个回文整数&#xff0c;返回true&#xff1b;否…

MIT6.828 Lab2-1 Using gdb

Using gdb gdb使用&#xff1a; xv6 gdb调试方法 问题1&#xff1a; Looking at the backtrace output, which function called syscall? 按照提示开启gdb后键入&#xff1a; b syscall c layout src backtrace输出结果&#xff1a; (gdb) backtrace #0 syscall () at k…

Python + adb 实现打电话功能

前言 其实很多年前写过一篇python打电话的功能&#xff0c;链接如下&#xff1a; Python twilio 实现打电话和发短信功能_自动发短信代码-CSDN博客 今天由于工作需要&#xff0c;又用python写了个关于打电话的小工具&#xff0c;主要是通过ADB方式实现的 实现过程 1.先利用…

YOLOv8+PyQt5鸟类检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

资源包含可视化的鸟类检测系统&#xff0c;基于最新的YOLOv8训练的鸟类检测模型&#xff0c;和基于PyQt5制作的可视化鸟类检测系统&#xff0c;包含登陆页面、注册页面和检测页面&#xff0c;该系统可自动检测和识别图片或视频当中出现的各种鸟类&#xff0c;以及自动开启摄像头…

Putty: 随心御剑——远程启动服务工具plink

一、引言:如何远程控制 也许你会有这样的场景,交互程序(以下简称UI程序)跑在windows端,而控制程序跑在Linux上。我们想要通过windows端 UI程序来启动Linux下面的服务,来一场酣畅淋漓的御剑飞行咋办,难道要自己十年磨一剑,在Linux下编写一个受控服务程序么.计算机科技发…

如何创建一个vue项目?详细教程,如何创建第一个vue项目?

已经安装node.js在自己找的到的地方新建一个文件夹用于存放项目&#xff0c;记住文件夹的存放路径&#xff0c;以我为例&#xff0c;我的文件夹路径为D:\tydic 打开cmd命令窗口&#xff0c;进入刚刚的新建文件夹 切换硬盘&#xff1a; D: 进入文件夹&#xff1a;cd tydic 使…

重学java 49 List接口

但逢良辰&#xff0c;顺颂时宜 —— 24.5.28 一、List接口 1.概述: 是collection接口的子接口 2.常见的实现类: ArrayList LinkedList Vector 二、List集合下的实现类 1.ArrayList集合的使用及源码分析 1.概述 ArrayList是List接口的实现类 2.特点 a.元素有序 —> 按照什么顺…

红外成像人员检测数据集VOC+YOLO格式5838张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5838 标注数量(xml文件个数)&#xff1a;5838 标注数量(txt文件个数)&#xff1a;5838 标注…

UE5 CommonUI的使用(附源码版)

UE5 CommonUI的使用 前言快速配置配置Game Viewport Client ClassCommonGameViewportClient源代码 创建CommonInputAction表默认导航Action设置CommonUIInputData源码 Bind CommonInputBaseControllerDataCommonInputBaseControllerData源码 Common UI控件库和控件样式CommonUs…

探索Python编程乐趣:制作气泡反弹小游戏

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;Python编程的轻松入门 二、游戏实现原理&#xff1a;气泡反弹的逻辑 …

echarts(6大基础图表)的使用

目录 一、vue2挂载 二、柱状图 2.1、基础柱状图介绍 2.2、标记&#xff1a;最大值\最小值(markPoint)、平均值(markLine) 2.3、显示&#xff1a;数值显示(label)、柱子宽度(barWidth)、横向柱状图 三、折线图 3.1、标记&#xff1a;最大值\最小值(markPoint)、平均值(ma…

微信资源混淆,导致的约束布局 Constraintlayout 控件重叠!

问题 1、广告六要素 虽然我不参与广告 sdk 接入等相关工作&#xff0c;但是最近总是听到一个词广告六要素。这到底是什么&#xff1f; 国内下载类广告&#xff0c;尤其是针对移动应用推广的广告&#xff0c;其成功实施往往围绕几个关键要素进行&#xff0c;这些要素能够帮助…

pcdn服务器应该怎么配?

要配置PCDN&#xff08;Private Content Delivery Network&#xff09;服务器&#xff0c;可以按照以下步骤进行&#xff1a; 需求分析&#xff1a;明确业务需求&#xff0c;确定所需的CDN功能和性能参数。这包括预期的流量、负载、内容类型、目标用户群体等。 硬件选择&#…

你真的懂firewalld吗?不妨看看我的这篇文章

一、firewalld简介 firewalld防火墙是Linux系统上的一种动态防火墙管理工具&#xff0c;它是Red Hat公司开发的&#xff0c;并在许多Linux发行版中被采用。相对于传统的静态防火墙规则&#xff0c;firewalld使用动态的方式来管理防火墙规则&#xff0c;可以更加灵活地适应不同…

MyBatis的基础操作

目录 一.什么是MyBatis? 二.使用MyBatis的准备工作 1.引入依赖: 2.配置数据库连接字符串(建立MaBatis和MySQL的连接) 3.在model包中建立数据库对应的实体类UserInfo 三.通过注解的方式实现MyBatis的开发 1.插入语句(Insert) 2.删除语句(Delete) 3.更新语句(Update) 4…

刚接触抖店并开通了个体店,怎么快速起店呢?运营思路参考如下

我是王路飞。 如果你刚接触抖店&#xff0c;并且开通了个体店&#xff0c;但不知道如何做店的话。 其实很简单&#xff0c;抖店的流程并没有这么复杂。 电商的核心无非就是产品&#xff0c;抖店的运营也都是围绕产品展开的。 我给你们说下抖店的运营思路你们可以作为参考&a…

李飞飞亲自撰文:大模型不存在主观感觉能力,多少亿参数都不行

近日&#xff0c;李飞飞连同斯坦福大学以人为本人工智能研究所 HAI 联合主任 John Etchemendy 教授联合撰写了一篇文章&#xff0c;文章对 AI 到底有没有感觉能力&#xff08;sentient&#xff09;进行了深入探讨。 「空间智能是人工智能拼图中的关键一环。」知名「AI 教母」李…

day16--集合进阶(Set、Map集合)

day16——集合进阶&#xff08;Set、Map集合&#xff09; 一、Set系列集合 1.1 认识Set集合的特点 Set集合是属于Collection体系下的另一个分支&#xff0c;它的特点如下图所示 下面我们用代码简单演示一下&#xff0c;每一种Set集合的特点。 //Set<Integer> set ne…

得物小程序逆向+qt可视化(不含sku)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

canvas层级太高?解决方法

这个方法主要是依赖于邀请好有页面展示的canvas二维码二维码以及其他容器的图片 有一个保存图片功能&#xff0c;这个保存图片是需要将二维码以及涉及到的其他容器比如下图&#xff1a; 所以这时候需要canvas来绘制一个保存图片的效果&#xff0c;然后对这个canvas绘制的图片保…