Vue基础5之绑定样式、条件渲染、列表渲染与Vue检测数据改变的原理

绑定样式

  1. class样式
    写法:class="xxx“ xxx可以是字符串、对象、数组
    字符串的写法适用于:类名不确定,要动态获取
    对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
    数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
  2. style样式
    :style="{fontSize:xxx}“其中xxx是动态
    :style=”[a,b]"其中a,b是样式对象

绑定class样式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>绑定样式</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <style>
    .basic{
      width: 400px;
      height: 100px;
      border: 1px solid black;
    }
    .happy{
      border: 5px solid red;
      background: linear-gradient(to top right,yellow 0%,orange 25%,pink 50%,yellow 75%,orange 100%);
    }
    .sad{
      background-color: #888;
      border: 5px greenyellow dashed;
    }
    .normal{
      background-color: skyblue;
    }
    .first{
      background-color: rgb(115, 231, 115);
    }
    .second{
      font-size: 30px;
      text-shadow: 2px 2px 5px pink;
    }
    .third{
      border-radius: 10px;
    }
  </style>
</head>
<body>
  <div id="root">
    <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
    <div class="basic" :class="mood" @click="changeMood">哈喽,你好{{name}}</div>  <br>

    <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
    <div class="basic" :class="classArr">哈喽,你好{{name}}</div>  
    <button @click="deleteClass">点击删除样式</button> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <input type="text" v-model="added">
    <button @click="addClass">点击添加样式</button>   <br><br>
    
    <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定,名字也确定,但是要动态决定用不用 -->
    <div class="basic" :class="classObj">哈喽,你好{{name}}</div>
    <button @click="chooseUse(0)">使用第一个样式,不使用第二个</button>
    <button @click="chooseUse(1)">不使用第一个样式,使用第二个样式</button>
    <button @click="chooseUse(2)">两个样式都使用</button>
    <button @click="chooseUse(3)">两个样式都不使用</button>
  </div>
</body>
<script>
  new Vue({
    el:"#root",
    data:{
      name:"张三",
      mood:"normal",
      classArr:["first","second","third"],
      classObj:{
        first:true,
        second:true
      },
      added:""
    },
    methods:{
      changeMood(){
        const arr=['normal','happy','sad']
        const r=Math.floor(Math.random()*3)     //随机数[0,n)的方法
        this.mood=arr[r]
      },
      deleteClass(){
        this.classArr.shift()
      },
      addClass(){
        this.classArr.push(this.added)
      },
      chooseUse(value){
        if(value==0){
          this.classObj.first=true
          this.classObj.second=false
        }else if(value==1){
          this.classObj.first=false
          this.classObj.second=true
        }else if(value==2){
          this.classObj.first=true
          this.classObj.second=true
        }else{
          this.classObj.first=false
          this.classObj.second=false
        }
      }
    }
  })
</script>
</html>

请添加图片描述
请添加图片描述
请添加图片描述

绑定style样式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>绑定style样式</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <!-- 原始写法 -->
    <div style="font-size: 40px;">你好啊</div>
    <hr>
    <!-- 绑定写法 -->
    <!-- 绑定style样式--对象写法 -->
    <div :style="styleObj">你好,{{name}}</div> <br>
    <!-- 绑定style样式--数组写法 -->
    <div :style="styleArr">欢迎来到{{school.name}}</div>

  </div>
</body>
<script>
  new Vue({
    el:"#root",
    data:{
      name:"张三",
      school:{
        name:"幸福中学"
      },
      styleObj:{
        fontSize: "40px",
        backgroundColor:"pink",
        color:"blue"
      },
      styleArr:[{
        fontSize: "50px",
        color:"red"
      },{
        backgroundColor:"skyblue",
        width:"500px",
        height:"150px"
      }]
    }
  })
</script>
</html>

请添加图片描述

条件渲染

  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一定可以获取到,
    (v-if 为false时,页面上没有元素了,通过其他办法无法获取,v-show为false,页面上还有这个元素,所以可以通过其他办法获取到)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>条件渲染</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <!-- 使用v-show做条件渲染 -->
    <button @click="isShow=!isShow">点击给你惊喜</button>  <br>
    <h1 v-show="isShow">你好,{{name}}</h1>
    <!-- 使用v-if做条件渲染 -->
    <button @click="isIf=!isIf">点击就能展示</button>   <br>
    <h1 v-if="isIf">欢迎来到{{school.name}}</h1>
    <hr>

    <!-- 用v-show -->
    <div>当前的n值是:{{n}}</div>
    <button @click="n++">点我n+1</button>
    <div v-show="n===1">Angular</div>
    <div v-show="n===2">React</div>
    <div v-show="n===3">Vue</div>

    <!-- 用v-if -->
    <div>当前的d值是:{{d}}</div>
    <button @click="d++">点我d+1</button>
    <div v-if="d===1">Angular</div>
    <div v-if="d===1">React</div>
    <div v-if="d===2">Vue</div>
    <hr>

    <!-- v-if,v-else-if,v-else使用,必须紧挨着 -->
    <div>当前的a值是:{{a}}</div>
    <button @click="a++">点我a+1</button>
    <div v-if="a===1">JavaScript</div>
    <!-- v-if执行后,则不会再执行v-else-if即便v-else-if也为true,这样代码执行效率能高点 -->
    <div v-else-if="a===1">Java</div>
    <div v-else-if="a===2">Jquery</div>
    <div v-else>哈哈哈</div>
    <hr>

    <!-- template和v-if配合使用 可以不打破原本结构-->
    <div>当前的b值是:{{b}}</div>
    <button @click="b++">点我b+1</button>
    <template v-if="b===1">
      <div>html,css</div>
      <div>JavaScript</div>
      <div>Dom,Bom</div>
    </template>
  </div>
</body>
<script>
  new Vue({
    el:"#app",
    data:{
      name:"张三",
      isShow:false,
      isIf:false,
      school:{
        name:"幸福中学"
      },
      n:0,
      d:0,
      a:0,
      b:0
    },

  })
</script>
</html>

请添加图片描述
请添加图片描述
请添加图片描述

列表渲染

v-for指令

v-for指令:

  1. 用于展示列表数据
  2. 语法:v-for=“(item,index) in xxx” :key=“yyy”
  3. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>列表渲染</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <!-- 遍历数组 -->
    <h2>人员列表(遍历数组)</h2>
    <ul>
      <li v-for="(p,index) in people" :key="p.id">
        {{index}}-{{p.name}}-{{p.age}}
      </li>
    </ul>

    <!-- 遍历对象 -->
    <h2>王老师信息(遍历对象)</h2>
    <ul>
      <li v-for="(value,k) of wang" :key="k">
        {{k}}-{{value}}
      </li>
    </ul>
    
    <!-- 遍历字符串 -->
    <h2>hello遍历(少用)</h2>
    <ul>
      <li v-for="(s,index) of str" :key="index">
        {{index}}-{{s}}
      </li>
    </ul>

    <!-- 遍历指定次数 -->
    <h2>数次数(少用)</h2>
    <ul>
      <li v-for="(number,index) of 6" :key="index">
        索引:{{index}}-数值:{{number}}
      </li>
    </ul>
  </div>
</body>
<script>
  new Vue({
    el:"#app",
    data:{
      people:[
        {id:"001", name:"张三", age:"18"},
        {id:"002", name:"李四", age:"19"},
        {id:"003", name:"王五", age:"20"}
      ],
      wang:{
        name:"王立春",
        merried:"已婚",
        sex:"女"
      },
      str:"hello"
    }
  })
</script>
</html>

请添加图片描述

key的原理

index作为key的时候

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>key的原理</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <ul>
      <li v-for="(p,index) in people" :key="index">
        {{p.name}}-{{p.age}} <input type="text">
      </li>
    </ul>
    <button @click="add">在列表最前面添加一个老刘</button>
  </div>
</body>
<script>
  new Vue({
    el:"#app",
    data:{
      people:[
        {id:"001",name:"张三",age:18},
        {id:"002",name:"李四",age:19},
        {id:"003",name:"王五",age:20}
      ]
    },
    methods:{
      add(){
        var obj={id:"004",name:"老刘",age:30}
        this.people.unshift(obj)
      }
    }
  })
</script>
</html>

若在列表中同时存在输入框时会出现以下问题:
请添加图片描述
出现问题的原因是Vue在生成虚拟dom时候使用对比(diff)算法,下面是运行过程图:
请添加图片描述

id作为key的时候

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>key的原理</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <ul>
      <li v-for="(p,index) in people" :key="p.id">
        {{p.name}}-{{p.age}} <input type="text">
      </li>
    </ul>
    <button @click="add">在列表最前面添加一个老刘</button>
  </div>
</body>
<script>
  new Vue({
    el:"#app",
    data:{
      people:[
        {id:"001",name:"张三",age:18},
        {id:"002",name:"李四",age:19},
        {id:"003",name:"王五",age:20}
      ]
    },
    methods:{
      add(){
        var obj={id:"004",name:"老刘",age:30}
        this.people.unshift(obj)
      }
    }
  })
</script>
</html>

请添加图片描述
就能得到正确结果,其运行过程如下所示:
请添加图片描述

总结

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

  1. 虚拟DOM中key的作用:
    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
  2. 对比规则:
    (1)旧虚拟DOM中找到了与新虚拟DOM中相同的key:
    ①若虚拟DOM中内容没变,直接使用之前的真实的DOM
    ②若虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    (2)旧虚拟DOM中未找到与新虚拟DOM中相同的key
    创建新的真实DOM,随后渲染到页面
  3. 用index作为key可能会引发的问题:
    (1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:
    会产生没有必要的真实DOM更新 =》页面效果没问题,但效率低
    (2)如果结构中还包含输入类的DOM:
    会产生错误DOM更新==》页面有问题
  4. 开发中如何选择key?
    ①最好使用每条数据唯一标识作为key,比如id,手机号、身份证号、学号等唯一值。
    ②如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

列表过滤

知识点补充:
对列表进行过滤时候可以使用filter过滤:
用法:
过滤出来的数组=数组.filter(()=>{
过滤条件
})

indexOf用法:
str.indexOf(“条件值”)

  • 若符合存在条件值的值,返回条件值在数组中的位置
  • 若不符合存在条件值的值,则返回-1
  • 若为空串,返回0

请添加图片描述

用监视属性实现

当immediate为true时,会在初始时候刷新一遍,则handler的val为"",对象的name值都符合条件,因此能在最初时都渲染在页面上

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>列表过滤</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <h1>人员列表</h1>
    <input type="text" v-model="keyword"> <br>
    <ul>
      <li v-for="(p,index) in filPeo" :key="p.id">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>
<script>
  new Vue({
    el:"#root",
    data:{
      keyword:"",
      people:[
        {id:"001",name:"马冬梅",age:19,sex:"女"},
        {id:"002",name:"周冬雨",age:20,sex:"女"},
        {id:"003",name:"周杰伦",age:21,sex:"男"},
        {id:"004",name:"温兆伦",age:22,sex:"男"}
      ],
      filPeo:[]
    },
    watch:{
      keyword:{
        immediate:true,
        handler(val){
          this.filPeo=this.people.filter((p) => {
            return p.name.indexOf(val)!=-1
          });
        }
      }
    }
  })
</script>
</html>

请添加图片描述
请添加图片描述

用计算属性实现(比监视属性简单)

不用再用另外一个数组装过滤后的东西了,直接用计算属性返回即可。
计算属性通过keyword计算出来结果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>列表过滤-计算属性</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <h1>人员列表</h1>
    <input type="text" v-model="keyword">
    <ul>
      <li v-for="(p,index) in filPeo" :key="p.id">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>
<script>
  new Vue({
    el:"#root",
    data:{
      keyword:"",
      people:[
        {id:"001",name:"马冬梅",age:19,sex:"女"},
        {id:"002",name:"周冬雨",age:20,sex:"女"},
        {id:"003",name:"周杰伦",age:21,sex:"男"},
        {id:"004",name:"温兆伦",age:22,sex:"男"}
      ]
    },
    computed:{
      filPeo(){
        return this.people.filter((p) => {
          return p.name.indexOf(this.keyword)!=-1
        })
      }
    }
  })
</script>
</html>

请添加图片描述

列表排序

知识点补充:
数组.sort((a,b)=>{
return a-b;
})
升序:return a-b;
降序:return b-a;

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>example</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <script>
    const arr=[15,30,10,8,45]
    //升序排序
    arr.sort((a,b) => {
      return a-b
    })
    console.log("arr经过升序排序之后得",arr);
    
    //降序排序
    const arr1=[15,30,10,8,45]
    arr1.sort((a,b) => {
      return b-a
    })
    console.log("arr经过降序排序之后得:",arr1);
  </script>
</body>
</html>

请添加图片描述
正式代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>列表排序</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <h1>人员列表</h1>
    <input type="text" placeholder="输入姓名" v-model="keyword"> 
    <button @click="sortType=2">年龄升序</button>
    <button @click="sortType=1">年龄降序</button>
    <button @click="sortType=0">原顺序</button>
    <ul>
      <li v-for="(p,index) in filPeo">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>
<script>
  new Vue({
    el:"#root",
    data:{
      people:[
        {id:"001",name:"马冬梅",age:35,sex:"女"},
        {id:"002",name:"周冬雨",age:20,sex:"女"},
        {id:"003",name:"周杰伦",age:25,sex:"男"},
        {id:"004",name:"温兆伦",age:15,sex:"男"}
      ],
      keyword:"",
      sortType:0
    },
    computed:{
      filPeo(){
        const arr= this.people.filter((p) => {
          return p.name.indexOf(this.keyword)!=-1
        })
        //判断一下是否需要排序
        if(this.sortType){
          //sort改变原数组
          arr.sort((a,b) => {
            return this.sortType!=1?a.age-b.age:b.age-a.age
          })
        }
        return arr 
      }
    }
  })
</script>
</html>

请添加图片描述

Vue检测数据改变的原理

更新时的一个小问题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>更新时的一个问题</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="root">
    <h1>人员列表</h1>
    <button @click="updateMa">更新马冬梅的信息</button>
    <button @click="updateYu">更新周冬雨的信息</button>
    <ul>
      <li v-for="(p,index) in people" :key="p.id">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>
<script>
  const vm=new Vue({
    el:"#root",
    data:{
      people:[
        {id:"001",name:"马冬梅",age:19,sex:"女"},
        {id:"002",name:"周冬雨",age:20,sex:"女"},
        {id:"003",name:"周杰伦",age:21,sex:"男"},
        {id:"004",name:"温兆伦",age:22,sex:"男"}
      ]
    },
    methods:{
      updateMa(){
        //此种方法修改有效
        this.people[0].name="马老师"
        this.people[0].age=50
        this.people[0].sex="男"
      },
      updateYu(){
        //此种方法修改无效
        this.people[1]={id:"002",name:"周老师",age:30,sex:"男"}
      }
    }
  })
</script>
</html>

请添加图片描述
可以发现,第一种写法,马冬梅的信息修改后能够有效,Vue能够检测到修改,但是第二种写法,从控制台输出可以发现,内存中周冬雨的那条数据已经修改了,但是Vue没有检测到修改,所以在页面上没有反应
请添加图片描述
加工data 就是 数据劫持

Vue检测对象数据原理

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue检测原理</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
</body>
<script>
  var data={
    name:"幸福中学",
    address:"上海"
  }

  //创建一个监视的实例对象,用于监视data中属性的变化
  var obs=new Observer(data)
  
  //写一个Observer的构造函数
  function Observer(obj){
    //汇总对象中所有的属性形成一个数组
    var keys=Object.keys(obj)
    console.log(keys);
    //遍历
    keys.forEach((k) => {
      //this指的是当前的实例对象
      Object.defineProperty(this,k,{
        get(){
          return obj[k]
        },
        set(val){
          console.log("${k}的值被修改了,我要去解析模板了");
          obj[k]=val
        }
      })
    })
  }

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

</script>
</html>

请添加图片描述

Vue.set()方法

Vue中的小bug:
  1. 如果是data中已有属性的属性值undefined不会显示,也不会出现bug
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <h2>姓名:{{student.name}}</h2>
        <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
        <!--  如果是data中已有属性的属性值undefined不会显示,也不会出现bug-->
        <h2>性别:{{student.sex}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}-{{f.age}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;

    const vm=new Vue({
        el:"#app",
        data:{
            school:{
                name:"幸福中学",
                address:"幸福路"
            },
            student:{
                name:"张三",
                age:{
                    rAge:40,
                    sAge:30
                },
                // sex:"男",
                friends:[
                    {name:"李四",age:20},
                    {name:"王五",age:25},
                ]
            }
        }
    })
</script>
</html>

在这里插入图片描述

  1. 如果是data的属性不存在就会出现问题
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h1>学生信息</h1>
    <h2>姓名:{{student.name}}</h2>
    <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
    <h2>性别:{{sex}}</h2>
    <h2>朋友们</h2>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}-{{f.age}}
        </li>
    </ul>
</div>
</body>
<script>
    Vue.config.productionTip=false;

    const vm=new Vue({
        el:"#app",
        data:{
            school:{
                name:"幸福中学",
                address:"幸福路"
            },
            // sex:"男",
            student:{
                name:"张三",
                age:{
                    rAge:40,
                    sAge:30
                },
                friends:[
                    {name:"李四",age:20},
                    {name:"王五",age:25},
                ]
            },
        }
    })
</script>
</html>

在这里插入图片描述

简单的给学生添加性别

额外的给对象设置属性

给vm._data.student添加是达不到响应式的,也不会有getter和setter方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <h2>姓名:{{student.name}}</h2>
        <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
        <!--  undefined不会显示,也不会出现bug-->
        <h2>性别:{{student.sex}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}-{{f.age}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;

    const vm=new Vue({
        el:"#app",
        data:{
            school:{
                name:"幸福中学",
                address:"幸福路"
            },
            student:{
                name:"张三",
                age:{
                    rAge:40,
                    sAge:30
                },
                // sex:"男",
                friends:[
                    {name:"李四",age:20},
                    {name:"王五",age:25},
                ]
            }
        }
    })
</script>
</html>

在这里插入图片描述
用vm.student.sex设置也是得到的同样的结果,在数据代理上并不会有所改变
在这里插入图片描述
用Vue.set()添加,就可以做响应式了,有getter和setter方法了。但是不能用在vm或者vm._data上面,不能对data直接 添加属性
在这里插入图片描述
用vm.$set()也可以做响应式效果
在这里插入图片描述
用方法添加性别

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <h2>姓名:{{student.name}}</h2>
        <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
        <!--  undefined不会显示,也不会出现bug-->
        <button @click="addSex">添加一个性别属性,默认值是男</button>
        <button @click="addGSex">添加一个性别属性,默认值是女</button>
        <h2 v-if="student.sex">性别:{{student.sex}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}-{{f.age}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;

    const vm=new Vue({
        el:"#app",
        data:{
            school:{
                name:"幸福中学",
                address:"幸福路"
            },
            student:{
                name:"张三",
                age:{
                    rAge:40,
                    sAge:30
                },
                // sex:"男",
                friends:[
                    {name:"李四",age:20},
                    {name:"王五",age:25},
                ]
            }
        },
        methods:{
            addSex(){
                Vue.set(this.student,'sex','男')
            },
            addGSex(){
                this.$set(this.student,'sex','女')
            }
        }
    })
</script>
</html>

请添加图片描述
注意: 对象不能是Vue实例,或者Vue实例的根数据对象

Vue检测数组数据原理

数组不像对象,数组中元素没有getter和setter方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        <h2>爱好</h2>
        <ul>
            <li v-for="(h,index) in hobby" :key="index">
                {{h}}
            </li>
        </ul>
        <hr>
        <h2>朋友</h2>
        <ul>
            <li v-for="(f,index) in friends" :key="index">
                {{f}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;

    const vm=new Vue({
        el:"#app",
        data:{
            name:"张三",
            age:20,
            hobby:['读书','看电影','画画'],
            friends:{
                f1:"王五",
                f2:"李四",
                f3:"赵六"
            }
        }
    })
</script>
</html>

在这里插入图片描述
使用直接修改方法不奏效
在这里插入图片描述
修改数组使用pop(),shift(),splice()这些
请添加图片描述
使用Vue.set()也可以对数组进行修改
请添加图片描述

总结Vue监视属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <button @click="student.age++">年龄+1岁</button>   <br>
        <button @click="addSex">添加性别属性,默认值:男</button>     <br>
        <button @click="student.sex='未知'">修改性别</button>
        <button @click="addFriend">在列表首位添加一个朋友</button>  <br>
        <button @click="updateFirstFriendName">修改第一个朋友名字:tom</button>  <br>
        <button @click="addHobby">添加一个爱好</button>    <br>
        <button @click="correctHobby">修改第一个爱好为:开车</button>
        <h2>姓名:{{student.name}}</h2>
        <h2>年龄:{{student.age}}</h2>
        <h2 v-if="student.sex">性别:{{student.sex}}</h2>
        <h2>爱好:</h2>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">
                {{h}}
            </li>
        </ul>
        <h2>朋友们:</h2>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}--{{f.age}}
            </li>
        </ul>
    </div>

</body>
<script>
    Vue.config.productionTip=false;
    const vm=new Vue({
        el:"#app",
        data:{
            student:{
                name:"张三",
                age:20,
                hobby:["看书","打游戏","画画"],
                friends:[
                    {name:"李四",age:30},
                    {name:"王五",age:35},
                ]
            }
        },
        methods:{
            addSex(){
                // Vue.set(this.student,"sex","男")
                this.$set(this.student,"sex","男")
            },
            addFriend(){
                this.student.friends.unshift({name:"jack",age:25})
            },
            updateFirstFriendName(){
                // this.student.friends.splice(0,1,{name:"tom",age:28})
                this.student.friends[0].name="tom"
                this.student.friends[0].age=15
            },
            addHobby(){
                this.student.hobby.push("唱歌")
            },
            correctHobby(){
                // this.student.hobby.splice(0,1,"开车")
                Vue.set(this.student.hobby,0,"开车")
                this.$set(this.student.hobby,0,"开车")
            }

        }
    })
</script>
</html>

请添加图片描述

Vue监视数据的原理:

  1. Vue会监视data中所有层次的数据
  2. 如何检测对象中的数据?
    通过setter实现监视,且要在new View时就传入要检测的数据
    (1)对象中后追加的属性,Vue默认不做响应式处理
    (2)如需给后添加的属性做响应式,请使用如下API:
    Vue.set(tartget,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的根数据对象 添加属性

对filter(),concat()和slice()这些非变更方法,不会改变原始数组,而总是返回一个新数组,当使用这些方法时候,可以用新数组替换旧数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>学生信息</h1>
        <button @click="removeRead">过滤掉读书的爱好</button>
        <h2>爱好</h2>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">
                {{h}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip=false;
    const vm=new Vue({
        el:"#app",
        data:{
            student:{
                hobby:["读书","看报","唱歌"]
            }
        },
        methods:{
            removeRead(){
                this.student.hobby=this.student.hobby.filter((h)=>{
                    return h!=="读书"
                })
            }
        }
    })
</script>
</html>

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值