Vue

直接更改watch中定义的数组的某个元素值,是否造成视图的变化

笔记

Posted by Wason on November 11, 2021

直接更改watch中定义的数组的某个元素值,是否造成视图的变化

在Vue中,用watch来响应监听数据的变化。包括:
(1) 监听某一数据的变化
(2) 监听对象或者数组的变化
(3) 监听对象或者数组某一属性的变化
(4) 监听路由的变化

(1) 监听某一数据的变化

<input type="text" v-model="userName"/>  
//当userName值发生变化时触发
watch: {
  userName (newName, oldName) {
    console.log(newName)
  }
}

第一种有一个缺点,就是当值第一次绑定的时候不会执行监听函数,只有当值改变的时候才会执行,如果我们想在第一次绑定的时候执行此监听函数 则需要 设置immediate为true

//当userName值发生变化时触发
watch: {
  userName: {
    handler (newName, oldName) {
      console.log(newName)
    },
    immediate: true
  }
}

(2) 监听对象或者数组的变化
当需要监听对象的改变时,此时就需要设置deep为true, 如果数组或对象采用 =(直接赋值的方法)普通监听也是可以监听到的。

<input type="text" v-model="cityName.name" />
data (){
  return {
    cityName: {name:'北京'}
  }
},
watch: {
  cityName: {
    handler(newName, oldName) {
      console.log(newName)
    },
    immediate: true,
    deep: true
  }
}

(3) 监听对象或者数组某一属性的变化 watch添加deep:true深度监听,只能监听到属性值的变化,新增、删除属性无法监听,下方有解决方法。

watch: {
  'cityName.name': {
    handler(newName, oldName) {
      console.log(newName)
    },
    immediate: true,
    deep: true
  }
}

(4) 监听路由的变化

watch:{
  '$route.path':function(newVal,oldVal){
    //console.log(newVal+"---"+oldVal);
    if(newVal === '/login'){
      console.log('欢迎进入登录页面');
    } else if(newVal === '/register'){
      console.log('欢迎进入注册页面');
    }
  }
}

watch:{
  $route(to,from){
    console.log(to.path);
  }
},

实例

Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)。然而它可以使用Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上,这样对象就变成了响应式的了,以下的方法就都可以使用了,此外动态添加新的根级响应式属性还可以用=、push、pop、shift、unshift、splice、sort、reverse(使用=的时候必须整体赋值 arr=[…],不能arr[0]=…。这样添加的属性是不具备响应式属性的,无setter/getter)

下面展示一些 内联代码片。


<template>
  <div>
    <ul>
      <li v-for="(item, index) in arr" :key="index"></li>
    </ul>
    <ul>
      <li v-for="(item, index) in obj" :key="index"></li>
    </ul>
    <button @click="tapme">点击我</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: [1, 2, 3, { name: "cui" }],
      obj: {
        name: "cui",
        age: 18,
        sex: "",
      },
    };
  },
  methods: {
    tapme() {
        //以下的操作都是在data中的内容都是一开始就定义好的,这样才是响应式的,才能有以下的操作,若一开始只是声明了一下,却没有赋值,而是在某个操作中直接赋值的话(不是使用$set的方法(响应式)),修改后就失去了getter、setter。下面的部分操作便会失效(标注)
        //操作数组
        this.arr[0]=100; //视图不变化 watck监听不到

        this.arr = [4,5,6,{name:"liu"}] //视图变化 watch可以监听到
        this.arr[3].name = "liu"; //视图变化 watch 深度监听可以监听到
        this.$set(this.arr,0,100) //视图变化   watch可以监听到
        this.arr.splice(0,1,100) //视图变化 watch可以监听到
        let tempArr = [...this.arr];
        tempArr[0]=100;
        this.arr = tempArr; //临时变量中转 视图变化watch可以监听到

       //操作对象
       this.obj.class = "good" //视图不变化  watck监听不到
       delete this.obj.name //视图不变化  watck监听不到

        this.obj={name:"liu",age:18,sex:""} //视图变化  watch可以监听到
        this.obj.name = "liu" //视图变化  watch 深度监听可以监听到
        this.$delete(this.obj,"name") //视图更新 同this.$set() watch可以监听到
        this.$set(this.obj,"email","www") // 视图变化  watch可以监听到
        this.obj = Object.assign({},this.obj,{class:"goods"}) //视图变化  watch可以监听到
    },
  },
  watch: {
    arr(){
        console.log("arr变化了")
    },
    arr: {
      handler: function () {
        console.log("arr变化了");
      },
      deep: true,
    },

    obj() {
      console.log("obj变化了");
    },
    obj: {
      handler: function () {
        console.log("obj变化了");
      },
      deep: true,
    }
  },
};
</script>

参考文章

vue中watch的详细用法以及更改数据视图是否更新(四种)