十四天学会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 = false
    const 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  非零值代表true
                    if (this.sortType) {
                        arr.sort((p1, p2) => {
                            //这一次提到sortType是为了判断是不是为1
                            return 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 = false
			
			const 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 = val
                console.log('name被修改')
            }
        })


    </script>

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

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

<script>
        let data = {
            name: '哈哈哈',
            address: '河南'
        }
        const obs = new Observer(data)
        // 准备一个实例
        let vm = {}
        //将我们写出来的obs给data和vm._data
        vm._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的根数据对象 添加属性!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

免费wordpress中文主题

免费大图wordpress主题 首页是一张大图的免费wordpress主题模板。简洁实用&#xff0c;易上手。 https://www.jianzhanpress.com/?p5857 免费WP模板下载 顶部左侧导航条的免费WP模板&#xff0c;后台简洁&#xff0c;新手也可以下载使用。 https://www.jianzhanpress.com/…

idea改了代码,但是需要紧急切换分支,需要把改动的保存到本地

但是如果有冲突&#xff0c;你没有合并&#xff0c;那也会丢哦&#xff01; 改完那个分支&#xff0c;回到这个分支然后弹出来再。

WGCLOUD使用下发指令重启安卓设备

wgcloud的下发命令很好使&#xff0c;可以下发很多命令&#xff0c;最好的是可以选择很多主机同时下发命令 这里我想重启下我的安卓设备&#xff0c;只需要下发一个命令&#xff1a; bash reboot 就好啦 如下图

微信公众号完成自动回复,自定义菜单

微信公众号完成自动回复&#xff0c;自定义菜单 首先要获取到微信公众号的开发者权限&#xff0c;这一步省略&#xff0c;可以自行百度 微信公众号对接自己的服务器 首先第一步需要有自己的服务器和固定的ip&#xff0c; 其中&#xff0c;80/443端口需要有其中一个&#xff0…

按尺寸筛选轮廓图中的轮廓

1.按短边筛选 原始轮廓图&#xff1a; import cv2 import numpy as np# 读取轮廓图 contour_image cv2.imread(..\\IMGS\\pp_edge.png, cv2.IMREAD_GRAYSCALE)# 使用cv2.findContours()函数获取所有轮廓 contours, _ cv2.findContours(contour_image, cv2.RETR_EXTERNAL, cv2…

据阿谱尔APO Research调研显示,2023年全球绝缘栅双极晶体管(IGBT)市场销售额约为89.9亿美元

根据阿谱尔 (APO Research&#xff09;的统计及预测&#xff0c;2023年全球绝缘栅双极晶体管&#xff08;IGBT&#xff09;市场销售额约为89.9亿美元&#xff0c;预计在2024-2030年预测期内将以超过14.7%的CAGR&#xff08;年复合增长率&#xff09;增长。 由于各行业对电力电子…

XSKY CTO 在英特尔存储技术峰会的演讲:LLM 存储,架构至关重要

5 月 17 日&#xff0c;英特尔存储技术峰会在北京顺利举办。作为英特尔长期的合作伙伴&#xff0c;星辰天合受邀参加了此次峰会。星辰天合 CTO 王豪迈作为特邀嘉宾之一&#xff0c;作了主题为《LLM 存储&#xff1a;架构至关重要》的演讲&#xff0c;分享了大语言模型&#xff…

jmeter发送webserver请求和上传请求

有时候在项目中会遇到webserver接口和上传接口的请求&#xff0c;大致参考如下 一、发送webserver请求 先获取登录接口的token&#xff0c;再使用cookie管理器进行关联获取商品(webserver接口)&#xff0c;注意参数一般是写在消息体数据中&#xff0c;消息体有点像HTML格式 执…

Java整合EasyExcel实战——2 导出复杂表头

详情代码 实体类 Data public class ComplexHeadData {ExcelProperty({"主标题", "字符串标题"})private String string;ExcelProperty({"主标题", "日期标题"})private Date date;ExcelProperty({"主标题", "数字标…

(2024,DDDM,ODE,少量步生成,迭代生成)直接去噪扩散模型

Directly Denoising Diffusion Model 公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 直接去噪扩散模型 3.1. 迭代求解 4. Psuedo-LPIPS 指标 5. 实验 7. 讨论和局限性 0. 摘…

大模型时代的具身智能系列专题(二)

李飞飞团队 李飞飞是华人在AI领域最具影响力的学者之一&#xff0c;她是斯坦福大学人工智能实验室&#xff08;SAIL&#xff09;教授&#xff0c;美国国家工程院院士&#xff0c;知名CV数据集ImageNet的牵头人&#xff0c;斯坦福视觉与学习实验室&#xff08;SVL&#xff09;的…

2024.05.27学习记录

1、面经复习&#xff1a; 实际工作经验章节 2、代码随想录刷题&#xff1a;动态规划剩下部分和单调栈 3、rosebush 组件库完成Input 和 AutoComplete部分内容

长难句打卡5.27

In fact, allowing non-lawyers to own shares in law firms would reduce costs and improve services to customers, by encouraging law firms to use technology and to employ professional managers to focus on improving firms’efficiency. 事实上&#xff0c;这通过…

can设备调试 - linux driver

这篇文章主要介绍can设备的调试相关信息&#xff0c;不具体介绍驱动的实现。 如果驱动写完&#xff0c;对can设备进行验证&#xff0c;可能会出现很多不可预见的问题。下面说说验证步骤 验证can设备可以使用工具can-utils。这个工具包中会有cansend candump等程序。可以直接通…

视频监控技术前沿探索:智能化趋势与EasyCVR视频汇聚技术应用

在数字化时代的浪潮中&#xff0c;视频监控技术以其独特的优势&#xff0c;正在安防领域书写着新的篇章。它不仅为公共安全部门提供了强大的技术支持&#xff0c;还深入到教育、政府、娱乐、医疗、酒店、运动等多个领域&#xff0c;成为维护社会秩序、保障人民安全的重要工具。…

python爬虫学习(2)——requests模块

520那天我向心仪的女孩要微信&#xff1a;“女神&#xff0c;能给我你的微信号吗&#xff1f;” 女神&#xff1a;“给我——爬&#xff01;&#xff01;&#xff01;&#xff01;” 从那天开始&#xff0c;我就决定要学好爬虫&#xff0c;爬到女神微信号&#xff01;&#xff…

分布式锁的原理和实现(Go)

文章目录 为什么需要分布式锁&#xff1f;go语言分布式锁的实现Redis自己的实现红锁是什么别人的带红锁的实现 etcdzk的实现 面试问题什么是分布式锁&#xff1f;你用过分布式锁吗&#xff1f;你使用的分布式锁性能如何&#xff0c;可以优化吗&#xff1f;怎么用Redis来实现一个…

CHI Read传输——CHI(3)

目录 一、Read操作概览 二、DMT(Direct Memory Transfer) 三、DCT (Direct Cache Transfer) 四、without Direct Data Transfer 五、ReadNoSnp and ReadOnce* structure with DMT 本篇我们来介绍一下CHI传输类型中的Read 一、Read操作概览 read操作有以下几种&#xff1…

详解CSS(二)

目录 1.背景属性 1.1背景颜色 1.2背景图片 1.3背景平铺 1.4背景位置 1.5背景尺寸 2.圆角矩形 3.元素的显示模式 3.1行内元素/内联元素&#xff08;Inline element&#xff09; 3.2块级元素&#xff08;Block-level element&#xff09; 3.3行内块元素&#xff08;In…

css-垂直居中的几种写法

图示 1、使用line-height属性&#xff08;当div有固定高度时&#xff09; 2、使用flexbox布局