Vue2-绑定样式、条件渲染、列表渲染、列表过滤、模糊查询、Vue监测数据原理

news2024/11/28 8:51:04

🥔:想只有苦难,做才有答案

更多Vue知识请点击——Vue.js

VUE2-Day3

    • 绑定样式
      • 1、class绑定
      • 2、绑定style样式
    • 条件渲染
      • 1、v-show
      • 2、v-if
      • 条件渲染案例
    • 列表渲染
      • 1、v-for
      • 2、key的作用与原理(重要)
        • 面试题:react、vue中的key有什么作用?(key的内部原理)
        • 案例:给数组头部添加一个人
    • 列表过滤:实现模糊查询
      • 1、使用watch实现
      • 2、使用computed实现
    • 列表排序
    • Vue监测数据原理及其方法
      • 1、更新数据时的一个问题
      • 2、模拟Vue监视data对象中的数据
      • 3、Vue监测对象中的数据
        • (1)怎么监测对象中的数据?
        • (2)`Vue.set()`的使用
      • 4、Vue监测数组中的数据
        • 如何监测数组中的数据?
      • 5、回头看第一个
      • 监测数据综合案例

绑定样式

1、class绑定

写法:class=“xxx” xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
数组写法适用于:要绑定多个样式,但是不确定绑定哪几个,就写成数组,省的一个一个绑定。
对象写法适用于:要绑定多个样式,而且要动态决定用不用,这里面可以写一些判断的逻辑。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>绑定class样式</title>
    <!-- 引入vue.js文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <!-- 设置css样式 -->
    <style>
      .basic {
        width: 400px;
        height: 100px;
        border: solid 1px black;
        margin-top: 50px;
      }
      .happy {
        background-color: pink;
      }
      .normal {
        background-color: greenyellow;
      }
      .sad {
        background-color: grey;
      }
      .style1 {
        background-color: skyblue;
      }
      .style2 {
        font-size: 28px;
      }
      .style3 {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <!--   :是v-bind:的简写 -->
      <!--   1. 绑定class样式--字符串写法,适用于样式的类名不确定,需要动态指定-->
      <div class="basic" :class="mood" @click="changeMood">{{name}}</div>

      <!--   2. 绑定class样式--数组写法,适用于要绑定的样式个数不确定,名字也不确定-->
      <div class="basic" :class="classArr" @click="removeStyle">{{name}}</div>
      <br />

      <!--   3. 绑定class样式--对象写法,适用于要绑定的样式个数确定,名字也确定,要动态决定用不用-->
      <div class="basic" :class="classObj">{{name}}</div>
      <br />
      <button @click="useStyle1">点击添加样式1</button>
      <button @click="useStyle2">点击添加样式2</button>
    </div>

    <script type="text/javascript">
      const vm = new Vue({
        el: "#root",
        data: {
          name: "我是最棒滴!!!",
          mood: "normal",
          classArr: ["style1", "style2", "style3"],
          classObj: {
            style1: false,
            style2: false,
          },
        },
        methods: {
          changeMood() {
            const arr = ["happy", "normal", "sad"];
            const index = Math.floor(Math.random() * 3);
            this.mood = arr[index];
          },
          //点击去掉第二个框的style样式
          //由于pop()是删掉最后一个元素,所以多次点击依次删除style3->style2->style1
          removeStyle() {
            this.classArr.pop();
          },
          //点击添加样式1
          useStyle1() {
            this.classObj.style1 = true;
          },
          //点击添加样式2
          useStyle2() {
            this.classObj.style2 = true;
          },
        },
      });
    </script>
  </body>
</html>
  • 可以拿此例子自己敲敲,多到浏览器运行调试看看

2、绑定style样式

:style="{fontSize: xxx + 'px'}"其中xxx是动态值。
:style="[a,b]"其中a、b是样式对象。

对象写法比较常用。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>绑定style样式</title>
    <!-- 引入vue.js文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <!-- 设置css样式 -->
    <style>
      .basic {
        width: 400px;
        height: 100px;
        border: solid 1px black;
        margin-top: 50px;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <!-- 绑定style样式-对象写法 -->
      <div class="basic" :style="styleObj1">{{name}}</div>
      <!-- 绑定style样式-数组写法 -->
      <div class="basic" :style="[styleObj1,styleObj2]">{{name}}</div>
      <div class="basic" :style="styleArr">{{name}}</div>
    </div>

    <script type="text/javascript">
      const vm = new Vue({
        el: "#root",
        data: {
          name: "我是最棒的!!!",
          styleObj1: {
            fontSize: "40px",
            backgroundColor: "pink",
          },
          styleObj2: {
            color: "red",
          },
          styleArr: [
            {
              fontSize: "40px",
              backgroundColor: "blue",
            },
            {
              color: "yellow",
            },
          ],
        },
      });
    </script>
  </body>
</html>

条件渲染

1、v-show

写法:v-show=“表达式”
适用于:切换频率较高的场景。(不会动DOM树,只是隐藏,相当于添加display:none)
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。这是因为v-if会一不小心把标签直接从页面上干掉,而v-show不会干掉,只会隐藏。

2、v-if

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

条件渲染案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>条件渲染</title>
    <!-- 引入vue文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <!-- 使用v-show做条件渲染:v-show值为true时显示,为false时隐藏(display: none) -->
      <h1 v-show="true">你好呀,{{name}}</h1>
      <h1 v-show="1===1">你好呀,{{name}}</h1>

      <!-- 使用v-if做条件渲染,v-if="false"时会彻底删除标签-->
      <h1 v-if="true">再见,{{name}}</h1>
      <h1 v-if="1===3">再见,{{name}}</h1>

      <!-- 实现功能:随着n递增展示不同的div -->
      <h2>{{n}}</h2>
      <button v-on:click="n++">点击n+1</button>

      <!-- 这里的v-if,v-else-if,v-else和基础js里的一样儿 -->
      <div v-if="n === 1">Angular</div>
      <div v-else-if="n === 2">React</div>
      <div v-else-if="n === 3">Vue</div>
      <div v-else>potato</div>

      <!-- v-if和template的配合使用(v-show不行)
    template不会影响页面结构,页面运行后会自动去掉,但是可以配合v-if控制多个元素整体显示
    而且不会影响css拿节点-->
      <template v-if="n === 1">
        <div>鱿鱼西一号</div>
        <div>鱿鱼西二号</div>
        <div>鱿鱼西三号</div>
      </template>
    </div>

    <script type="text/javascript">
      const vm = new Vue({
        el: "#root",
        data: {
          name: "鱿鱼西",
          n: 0,
        },
      });
    </script>
  </body>
</html>

列表渲染

1、v-for

  1. 用于展示列表数据

  2. 语法:v-for=“(item, index) in xxx” :key=“yyy”,其中xxx是遍历的目标,yyy是唯一的索引,用于区分每个嘎达

  3. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

  4. 遍历数组的话,index是索引值(唯一),p是数组每个元素

  5. 遍历对象的话,index就是属性名(唯一),p是属性值

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>基本列表渲染</title>
    <!-- 引入vue文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组:遍历数组的话,index是索引值,p是数组每个元素  -->
      <h2>人员列表(遍历数组)</h2>
      <ul>
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}}-{{p.age}}-{{index}}
        </li>
      </ul>

      <!-- 遍历对象:遍历对象的话,index就是属性名,p是属性值 -->
      <h2>汽车信息(遍历对象)</h2>
      <ul>
        <li v-for="(p,index) of car" :key="index">{{p}}-{{index}}</li>
      </ul>

      <!-- 遍历字符串:遍历字符串的话,index就是索引值,p是每个字符 -->
      <h2>遍历字符串</h2>
      <ul>
        <li v-for="(p,index) of str" :key="index">{{p}}-{{index}}</li>
      </ul>

      <!-- 遍历指定次数:遍历指定次数的话,index就是索引值,p是从1开始数 -->
      <h2>遍历指定次数</h2>
      <ul>
        <li v-for="(p,index) of 5" :key="index">{{p}}-{{index}}</li>
      </ul>
    </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 },
          ],
          car: {
            name: "马沙拉弟",
            price: "10块钱",
            color: "骚粉色",
          },
          str: "hello",
        },
      });
    </script>
  </body>
</html>

2、key的作用与原理(重要)

ey可以有三种情况:写唯一标识、写index、不写。其中唯一标识最合适,如果不写会默认是写index。

面试题:react、vue中的key有什么作用?(key的内部原理)

1、 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较(diff算法),比较规则如下:

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是没有问题的。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>key的原理和作用</title>
    <!-- 引入vue文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组:遍历数组的话,index是索引值,p是数组每个元素  -->
      <h2>人员列表(遍历数组)</h2>
      <button @click="add">点击添加老六</button>
      <ul>
        <!-- index-索引号,p.id-唯一标识符 -->
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}}-{{p.age}}-{{index}}
          <input type="text" />
        </li>
      </ul>
    </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 },
          ],
        },
        methods: {
          add() {
            const p = { id: "004", name: "老六", age: 19 };
            // unshift():此方法的作用是将指定元素添加到数组的开头
            this.persons.unshift(p);
          },
        },
      });
    </script>
  </body>
</html>

案例:给数组头部添加一个人

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>key的原理和作用</title>
    <!-- 引入vue文件 -->
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组:遍历数组的话,index是索引值,p是数组每个元素  -->
      <h2>人员列表(遍历数组)</h2>
      <button @click="add">点击添加老六</button>
      <ul>
        <!-- index-索引号,p.id-唯一标识符 -->
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}}-{{p.age}}-{{index}}
          <input type="text" />
        </li>
      </ul>
    </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 },
          ],
        },
        methods: {
          add() {
            const p = { id: "004", name: "老六", age: 19 };
            // unshift():此方法的作用是将指定元素添加到数组的开头
            this.persons.unshift(p);
          },
        },
      });
    </script>
  </body>
</html>

遍历列表时key的作用(index作为key):

请添加图片描述

遍历列表时key的作用(唯一标识作为key):

请添加图片描述

列表过滤:实现模糊查询

1、使用watch实现

handler函数必须在keyword被改变时才执行,也就是说页面上来还是没有信息的,必须手动输入个东西再删掉(手动改变keyword),才能执行handler函数,才能显示所有人物的信息,所以必须加个属性immediate: true,才能默认初始化先调用handler,这样就能实现上来就显示所有人物的信息(最开始keyword=''

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表过滤</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <h2>人员列表</h2>
      <input type="text" placeholder="请输入关键字" v-model="keyWord" />
      <ul>
        <li v-for="(p,index) of filPersons" :key="p.id">
          {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
      </ul>
    </div>

    <script type="text/javascript">
      //   用监视(侦听)属性watch实现
      new Vue({
        el: "#root",
        data: {
          keyWord: "",
          persons: [
            { id: "001", name: "马冬梅", age: 18, sex: "女" },
            { id: "002", name: "周冬雨", age: 19, sex: "女" },
            { id: "003", name: "周杰伦", age: 18, sex: "男" },
            { id: "004", name: "温兆伦", age: 18, sex: "男" },
          ],
          filPersons: [],
        },
        watch: {
          keyWord: {
            //页面上来由于filPersons是空,不会显示数据,想要让页面初始化就显示所有人,就要加个immediate: true
            //这样就可以让handler函数初始化时先调用一次,由于开始keyword=''
            // 而字符串里都包含空字符串,就可以先筛选出来,初始化所有人物信息
            immediate: true,
            handler(newVal, oldVal) {
              this.filPersons = this.persons.filter((p) => {
                //判断keyword变化后的新值在不在每个对象的name中,并返回一个新的数组
                return p.name.indexOf(newVal) !== -1;
              });
            },
          },
        },
      });
    </script>
  </body>
</html>

2、使用computed实现

使用计算属性可以解决watch中的一些繁琐写法,也不用在data中再新定义一个空数组newPersons。

计算属性和监视属性最大的区别就是handler函数是被监视的属性更改时执行,而get是属性被读取时就执行,所以页面加载时filPersons被读取直接就调用get函数返回了一个被筛选后的新数组(条件是name包含空字符串),之后每次keyword改动都会导致Vue模板重新解析,get重新调用。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表过滤</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <h2>人员列表</h2>
      <input type="text" placeholder="请输入关键字" v-model="keyWord" />
      <ul>
        <li v-for="(p,index) of filPersons" :key="p.id">
          {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
      </ul>
    </div>

    <script type="text/javascript">
      //用计算属性computed实现;
      new Vue({
        el: "#root",
        data: {
          keyWord: "",
          persons: [
            { id: "001", name: "马冬梅", age: 18, sex: "女" },
            { id: "002", name: "周冬雨", age: 19, sex: "女" },
            { id: "003", name: "周杰伦", age: 18, sex: "男" },
            { id: "004", name: "温兆伦", age: 18, sex: "男" },
          ],
        },
        computed: {
          filPersons() {
            return persons.filters((p) => {
              return p.name.indexOf(this.keyWord) !== -1;
            });
          },
        },
      });
    </script>
  </body>
</html>

列表排序

先过滤,再排序
首先定义一个sortType属性来判断排序的种类,然后在计算属性里做一个判断。
注意这里仔细理解理解数组的sort方法,很奇怪。
这个案例再次体现出计算属性的强大之处,只要get里用到的数据(keyword,sortType)发生改变,get都会重新执行,模板都会重新解析,这个业务逻辑就实现了

先复习一下数组的排序sort升序降序方法

      let arr = [1, 5, 3, 7, 4];
      //降序b-a
      //   arr.sort((a, b) => {
      //     return b - a;
      //   });
      //   console.log(arr);

      //升序a-b
      arr.sort((a, b) => {
        return b - a;
      });
      console.log(arr);

例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表排序</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备好一个容器 -->
    <div id="root">
      <h1>人员列表</h1>
      <input type="text" placeholder="请输入关键字" v-model="keyword" />
      <button @click="sortType = 0">原顺序</button>
      <button @click="sortType = 1">年龄降序</button>
      <button @click="sortType = 2">年龄升序</button>
      <ul>
        <li v-for="(p,index) in newPersons" :key="p.id">
          {{p.name}}----{{p.age}}----{{p.sex}}
        </li>
      </ul>
    </div>

    <script>
      const vm = new Vue({
        el: "#root",
        data: {
          sortType: 0, //0原顺序,1年龄降序,2年龄升序
          keyword: "",
          persons: [
            { id: "001", name: "马冬梅", age: 18, sex: "女" },
            { id: "002", name: "周冬雨", age: 19, sex: "女" },
            { id: "003", name: "周杰伦", age: 30, sex: "男" },
            { id: "004", name: "温兆伦", age: 50, sex: "男" },
          ],
        },
        computed: {
          newPersons() {
            //先过滤,再排序
            const arr = this.persons.filter((ele) => {
              return ele.name.includes(this.keyword);
            });

            // 或者if(this.sortType)
            if (this.sortType !== 0) {
              arr.sort((a, b) =>
                this.sortType === 1 ? b.age - a.age : a.age - b.age
              );
            }
            return arr;
          },
        },
      });
    </script>
  </body>
</html>

Vue监测数据原理及其方法

1、更新数据时的一个问题

如果我要点击按钮实现更新马冬梅的信息,那么如果一个属性一个属性地改,可以修改成功,并且Vue也会检测到并更新到页面。但是我如果直接把整个对象改了,可以修改成功,但是Vue监测不到并且不更新到页面,这是为什么?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表排序</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备好一个容器 -->
    <div id="root">
      <h1>人员列表</h1>
      <button @click="updateMei">更新马冬梅信息</button>
      <ul>
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}}----{{p.age}}----{{p.sex}}
        </li>
      </ul>
    </div>

    <script>
      const vm = new Vue({
        el: "#root",
        data: {
          persons: [
            { id: "001", name: "马冬梅", age: 18, sex: "女" },
            { id: "002", name: "周冬雨", age: 19, sex: "女" },
            { id: "003", name: "周杰伦", age: 30, sex: "男" },
            { id: "004", name: "温兆伦", age: 50, sex: "男" },
          ],
        },
        methods: {
          updateMei() {
            // this.persons[0].name = "马老师"; //奏效(页面和Vue都监测到了)
            // this.persons[0].age = 28; //奏效(页面和Vue都监测到了)
            // this.persons[0].sex = "男"; //奏效(页面和Vue都监测到了)

            //此处Vue监测不到数据改变,但是实际上已经改了
            this.persons[0] = { id: "001", name: "马老师", age: 28, sex: "男" };
          },
        },
      });
    </script>
  </body>
</html>

2、模拟Vue监视data对象中的数据

用原生js写一个Vue监视data数据改变的效果
可以看出,Vue监视数据的原理,就是靠setter
如果不理解obj[k],想想前边讲Object.defineProperty时那个number

getter:当属性值被访问时,会触发getter方法,这时Vue会将当前的Watcher对象(即订阅者)存储起来,用于后续数据变化时的更新操作。

setter:属性被修改–>调用setter–>重新解析模板–>生成新的虚拟DOM–>新旧DOM对比(diff)–>更新页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script type="text/javascript">
      let data = {
        name: "小猪佩奇",
        age: 5,
      };
      //创建一个监视的实例对象,用于监视data中属性的变化
      const obs = new Observer(data);
      console.log(obs);

      //准备一个vm实例对象
      let vm = {};
      vm._data = data = obs;

      function Observer(obj) {
        //1.创建一个数组接收传入对象的属性名
        const keys = Object.keys(obj);
        //2.遍历属性名,让Observer实例对data中的每个数据进行数据代理
        keys.forEach((k) => {
          Object.defineProperty(this, k, {
            get() {
              //有人想读实例中的属性值,我就把data中对应的属性值拿过来
              return obj[k];
            },
            set(val) {
              console.log(
                `${k}被改了,我要去解析模板,生成虚拟DOM...我要开始忙了`
              );
              //有人想改实例中的属性值,我就把data中对应的属性值更改(数据代理)
              obj[k] = val;
            },
          });
        });
      }
    </script>
  </body>
</html>

这只是一个简单的模拟,实际上Vue做了更多事情,比如:
1、在setter中不是简单的输出,而是重新解析模板,生成虚拟DOM,新旧虚拟DOM对比,更新页面实现响应式。
2、Vue中vm还对_data做了数据代理,可以直接vm.name,不用vm._data.name
3、上面的简单模拟例子,如果数据是套娃的(对象中还有对象还有对象),就监测不到。但是Vue就可以,不管你数据藏得多深,Vue都能找到,每个数据都有自己的getter和setter。只要有数据被改,就会实现响应式。

3、Vue监测对象中的数据

(1)怎么监测对象中的数据?

1、vue会监视data中所有层次的数据,不管你藏得有多深。
2、如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:

Vue.set(target,propertyName/index,value) 或 
vm.$set(target,propertyName/index,value)

(2)Vue.set()的使用

用法:
向响应式对象中添加一个 property(属性),并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.girlfriend.sex = '女')为啥呢?

_data在收集data中的数据之前,先做了一个加工(这个加工也可以称之为数据劫持),那就是给每个数据匹配一个getter和setter,前面说了,Vue监视数据的原理,就是靠setter。所以如果我们后期手动直接给_data添加属性(注意区别手动添加和从data中收集),是无法实现响应式的,因为没办法给它setter,只有从data中收集过来的属性才能有setter。

Vue.set()是有局限性的!!!它只能给data中的某个对象追加属性,不能给vm 或 vm的根数据对象(data或_data) 添加属性!!!
也就是说第一个参数不能是 Vue 实例,或者 Vue 实例的根数据对象(_data)

<div id="root">
    <h2>我的名字:{{name}}</h2>
    <h2>我的年龄:{{age}}</h2>
    <!-- v-if当属性值为undefined不显示,也不报错 -->
    <h3 v-if="sex">我的性别:{{sex}}</h3>
    <button @click="addmySex">点击添加我的性别</button>
    <hr>
    <h2>她的名字:{{girlfriend.name}}</h2>
    <button @click="addherSex">点击添加性别,属性值为女</button>
    <h2 v-if="girlfriend.sex">她的性别:{{girlfriend.sex}}</h2><h2>她的年龄:对外{{girlfriend.age.fakeAge}},真实{{girlfriend.age.realAge}}</h2>
    <h2>朋友们</h2>
    <ul>
        <li v-for="p in girlfriend.friends" :key="p.id">
            {{p.name}}----{{p.age}}
        </li>
    </ul>
</div>
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            name: 'www',
            age: 18,
            girlfriend: {
                name: 'zzz',
                // sex: '女',
                age: {
                    realAge: 23,
                    fakeAge: 18
                }
            }
        },
        methods: {
            addherSex() {
                // Vue.set(this.girlfriend, 'sex', '女');
                this.$set(this.girlfriend, 'sex', '女');                         //vm.$set(vm.girlfriend, 'sex', '女');
            },
            addmySex() {
                Vue.set(this, 'sex', '男');
            }
        },
    })
</script>

4、Vue监测数组中的数据

如何监测数组中的数据?

Vue定义了一个非常厉害的方法,目的只有一个:实现响应式。

方法里包装的代码本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新。然后第二步在这个基础上再加东西
(2)重新解析模板,生成虚拟DOM,diff算法……进而更新页面,实现响应式。

所以在Vue修改数组中的某个元素实现响应式一定要用如下方法:
(1)使用这些API:push()在后面追加、pop()删除最后一个、shift()删除第一个、unshift()在前面追加、splice()在指定位置增删改、sort()数组排序、reverse()反转数组,这些api都是可以修改原数组的,可以在(MDN Web Docs (mozilla.org))查看。
(2)Vue.set()vm.$set()也可以实现响应式,第二个参数写索引,第三个写元素,可以改也可以加

5、回头看第一个

说了这么多,再回头看第一个问题,恍然大悟
1、单独改每个属性可以奏效,是因为Vue可以监测到对象里的每个属性,不管它藏的多深,只要是个对象,就有相应的getter和setter
2、将数组中的元素单独替换,数据修改成功,但是Vue没有监测到,页面不显示,这是因为数组中的每个元素是没有getter和setter的,如果修改数组中的元素无法实现响应式.
3、要想让更改数组中的元素实现响应式,就得调用数组的七个api或者用Vue.set()方法

解决:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>列表排序</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备好一个容器 -->
    <div id="root">
      <h1>人员列表</h1>
      <button @click="updateMei">更新马冬梅信息</button>
      <ul>
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}}----{{p.age}}----{{p.sex}}
        </li>
      </ul>
    </div>

    <script>
      const vm = new Vue({
        el: "#root",
        data: {
          persons: [
            { id: "001", name: "马冬梅", age: 18, sex: "女" },
            { id: "002", name: "周冬雨", age: 19, sex: "女" },
            { id: "003", name: "周杰伦", age: 30, sex: "男" },
            { id: "004", name: "温兆伦", age: 50, sex: "男" },
          ],
        },
        methods: {
          updateMei() {
            // this.persons[0].name = "马老师"; //奏效(页面和Vue都监测到了)
            // this.persons[0].age = 28; //奏效(页面和Vue都监测到了)
            // this.persons[0].sex = "男"; //奏效(页面和Vue都监测到了)

            //不奏效,此处Vue监测不到数据改变,但是实际上已经改了
            // this.persons[0] = { id: "001", name: "马老师", age: 28, sex: "男" };

            this.persons.splice(0, 1, {
              id: "001",
              name: "马老师",
              age: 28,
              sex: "男",
            });
          },
        },
      });
    </script>
  </body>
</html>

监测数据综合案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>数据监测综合案例</title>
    <script type="text/javascript" src="../js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <h1>学生信息</h1>

      <!-- 六个任务如下 -->
      <button @click="student.age++">年龄加1</button><br />
      <button @click="addSex">增加性别属性,默认值:男</button><br />
      <button @click="addFriend">在列表首位添加一个朋友</button><br />
      <button @click="updateFirstFriendName">
        修改第一个朋友的名字为:小张,年龄改为20</button
      ><br />
      <button @click="addHobby">添加一个爱好</button><br />
      <button @click="updateHobby">修改一个爱好为:开车</button><br />

      <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">
      const vm = new Vue({
        el: "#root",
        data: {
          student: {
            name: "小吴",
            age: 18,
            hobby: ["羽毛球", "乒乓球", "篮球"],
            friends: [
              { name: "小黄", age: 19 },
              { name: "小何", age: 19 },
            ],
          },
        },
        methods: {
          addSex() {
            Vue.set(this.student, "sex", "男");
            //this.$set(this.student, "sex", "男")
          },
          addFriend() {
            this.student.friends.unshift({ name: "小王", age: 18 });
          },
          updateFirstFriendName() {
            // this.student.friends[0].name = "小张";
            // this.student.friends[0].age = 20;
            // 另一种写法
            this.student.friends.splice(0, 1, { name: "小张", age: 20 });
          },
          addHobby() {
            this.student.hobby.push("排球");
          },
          updateHobby() {
            //把第二个修改为开车
            this.student.hobby.splice(1, 1, "开车");
            //this.$set(this.student.hobby,1,'开车')
          },
        },
      });
    </script>
  </body>
</html>

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

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

相关文章

Android 高手进阶教程(二)之----Android 数据库SQLiteDatabase的使用!!

直接进入主题~ Android 提供了三种数据存储方式&#xff0c;第一种是文件存储;第二种是SharedPreferences 存储;第三种就是数据库SQLiteDatabase 存储。 文件存储我就不用多说了&#xff0c;而SharedPreferences 可以存取简单的数据(int,double,float.etc)&#xff0c;它经常…

数字孪生有哪些应用场景?

数字孪生技术正在越来越普遍。根据艾瑞咨询2023年调查&#xff0c;2022年中国数字孪生市场规模为104亿&#xff0c;同比增长35.0%。随着各行业数字化转型的推进&#xff0c;国内未来数字孪生市场规模将继续增长&#xff0c;预计2023年国内市场规模将达到375亿元。 数字孪生是指…

图片预览插件vue-photo-preview的使用

移动端项目中需要图片预览的功能&#xff0c;但本身使用mintui&#xff0c;vantui中虽然也有&#xff0c;但是为了一个组件安装这个有点儿多余&#xff0c;就选用了vue-photo-preview插件实现&#xff08;其实偷懒也不想自己写&#xff09;。 1、安装 npm i vue-photo-preview…

学以致用:python面向对象和PyEcharts的完美混合技

文章目录 学习目标数据案例分析数据内容需求分析参考代码data_define.pyfile_define.pymain.py 学习目标 使用面向对象思想完成数据读取和处理基于面向对象思想重新认知第三方库使用(PyEcharts) 数据案例分析 数据内容 1月份数据是普通文本&#xff0c;使用逗号分割数据记录&…

生态系统服务(InVEST模型)

第一天&#xff1a; 1. 生态系统服务理论联系实践案例讲解 2. InVEST模型的开发历程、不同版本的差异及对数据需求的讲解 3. InVEST所需数据的要求&#xff08;分辨率、格式、投影系统等&#xff09;、获取及标准化预处理讲解 4. InVEST运行常见问题及处理解决方法讲解 5.…

基于 CentOS 7 构建 LVS-DR 群集 配置nginx负载均衡

环境配置&#xff1a; RHCE客户机192.168.100.146node1lvs192.168.100.145node2RS192.168.100.147node3RS192.168.100.148 配置ipvsadm httpd&#xff1a; [rootnode1 ~]# yum install ipvsadm.x86_64 [rootnode2 ~]# yum install http -y [rootnode2 ~]# systemctl …

Ubuntu18.04版本安装ROS及出现错误的处理方法

前面的文章是在已安装的ROS基础上做的一些应用&#xff0c;这里我们从零开始安装ROS机器人操作系统。 机器人操作系统(Robot Operating System,ROS)是一个开发机器人软件的框架&#xff0c;里面包含了一系列的工具&#xff0c;库和惯例&#xff0c;目的在于简化在大量不同种类机…

从一道面试题来学习前台进程和后台进程、孤儿进程和僵尸进程

1、面试题介绍 以前面试&#xff0c;面试官问了一个问题&#xff0c;大意是&#xff1a; 我们在终端中&#xff0c;通过执行 python main.py 命令&#xff0c;会启动一台前台进程直到程序结束。现在我还是想通过执行 python main.py &#xff0c;启动一个后台进程&#xff0c;…

k8s的yaml文件管理

声明式管理方法&#xff1a; 1.适合于对资源的修改操作2.声明式资源管理方法依赖于资源配置清单文件对资源进行管理资源配置清单文件有两种格式&#xff1a;yaml&#xff08;人性化&#xff0c;易读&#xff09;&#xff0c;json&#xff08;易于api接口解析&#xff09;3.对资…

【实操】2023年npm组件库的创建发布流程

2022年的实践为基础&#xff0c;2023年我再建一个组件库【ZUI】。步骤回顾&#xff1a; 2022年的npm组件包的发布删除教程_npm i ant-design/pro-components 怎么删除_啥咕啦呛的博客-CSDN博客 1.在gitee上创建一个项目,相信你是会的 2.创建初始化项目&#xff0c;看吧&#…

SpringBoot使用自定义事件监听器的demo

记录一下SpringBoot自定义事件监听器的使用方法 案例源码:SpringBoot使用自定义事件监听器的demo 使用的SpringBoot2.0.x版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><…

【Opencv入门到项目实战】(十):项目实战|文档扫描|OCR识别

所有订阅专栏的同学可以私信博主获取源码文件 文章目录 1.引言1.1 什么是光学字符识别 (OCR)1.2 应用领域 2.项目背景介绍3.边缘检测3.1 原始图像读取3.2 预处理3.3 结果展示 3.轮廓检测4.透视变换5.OCR识别5.1 tesseract安装5.2 字符识别 1.引言 今天我们来看一个OCR相关的文…

开发工具IDEA的下载与初步使用【各种快捷键的设置,使你的开发事半功倍】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于IDEA的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.IDEA的简介以及优势 二.IDEA的下载 1.下…

释放马氏距离的力量:用 Python 探索多元数据分析

一、说明 马哈拉诺比斯距离&#xff08;Mahalanobis Distance&#xff09;是一种测量两个概率分布之间距离的方法。它是基于样本协方差矩阵的函数&#xff0c;用于评估两个向量之间的相似程度。Mahalanobis Distance考虑了数据集中各个特征之间的协方差&#xff0c;因此比欧氏距…

skynet 网络模块解析

文章目录 前言环境准备sneak peek线程数据结构会话对象&#xff1a;持有基础套接字&#xff0c;封装了套接字的基础操作。会话管理器&#xff1a;持有并管理会话池&#xff0c;给外部模块提供网络接口。 网络模块管理会话管理器的生命周期管理工作模式 总结技术点原子数据管道描…

漫话拥塞控制:BBR 是个单流模型

概要(便于检索主题)&#xff1a;单流&#xff0c;多流收敛&#xff0c;probe buffer 挤压带宽&#xff0c;maxbw-filter wnd。 我曾经经常说 BBR 是个单流模型&#xff0c;而不是多流收敛模型&#xff0c;也做过不少评论&#xff0c;最近在复听 IETF 的大会&#xff0c;在 IET…

SQL | 检索数据

1-检索数据 1.1-检索单个列 SELECT prod_name FROM Products; 上述SELECT语句从Products表中检索一个名为prod_name的列。 所要查找的列在select后面&#xff0c;from关键字指出从那个表查询数据。 输出如下&#xff1a; prod_name8 inch teddy bear12 inch teddy bear18…

linux鲁班猫代码初尝试[编译镜像][修改根文件系统重编译][修改设备树改屏幕为MIPI]

编译镜像 官方百度云盘资料:https://doc.embedfire.com/linux/rk356x/quick_start/zh/latest/quick_start/baidu_cloud/baidu_cloud.html 解压虚拟机压缩包:"鲁班猫\8-SDK源码压缩包\开发环境虚拟机镜像\ubuntu20.04.7z"后既可以用VMware打开,打开后可以看到已经有…

【前端】JQ生成二维码

提供两种方法&#xff0c;两种都是借助JQ插件生成。 所需文件&#xff1a;https://download.csdn.net/download/qq_25285531/88204985https://download.csdn.net/download/qq_25285531/88204985 方法一&#xff1a; <script type"text/javascript" src"/s…

【JavaEE基础学习打卡02】是时候了解JavaEE了

目录 前言一、为什么要学习JavaEE二、JavaEE规范介绍1.什么是规范&#xff1f;2.什么是JavaEE规范&#xff1f;3.JavaEE版本 三、JavaEE应用程序模型1.模型前置说明2.模型具体说明 总结 前言 &#x1f4dc; 本系列教程适用于JavaWeb初学者、爱好者&#xff0c;小白白。我们的天…