精华内容
下载资源
问答
  • Vue检测数据变化

    2020-10-07 16:02:01
    Vue检测数据变化

    前言

    Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

    如何追踪变化

    当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

    这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。

    每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
    在这里插入图片描述

    检测变化的注意事项

    由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。

    对于对象

    Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

    var vm = new Vue({
      data:{
        a:1
      }
    })
    
    // `vm.a` 是响应式的
    
    vm.b = 2
    // `vm.b` 是非响应式的
    

    对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于:

    Vue.set(vm.someObject, 'b', 2)
    

    您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

    this.$set(this.someObject,'b',2)
    

    有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign()_.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

    // 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
    this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
    

    对于数组

    Vue 不能检测以下数组的变动:

    1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
    2. 当你修改数组的长度时,例如:vm.items.length = newLength

    举个例子:

    var vm = new Vue({
      data: {
        items: ['a', 'b', 'c']
      }
    })
    vm.items[1] = 'x' // 不是响应性的
    vm.items.length = 2 // 不是响应性的
    

    为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:

    // Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
    

    你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

    vm.$set(vm.items, indexOfItem, newValue)
    

    为了解决第二类问题,你可以使用 splice:

    vm.items.splice(newLength)
    

    声明响应式 property

    由于 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式 property,哪怕只是一个空值:

    var vm = new Vue({
      data: {
        // 声明 message 为一个空值字符串
        message: ''
      },
      template: '<div>{{ message }}</div>'
    })
    // 之后设置 `message`
    vm.message = 'Hello!'
    

    如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问不存在的 property。

    这样的限制在背后是有其技术原因的,它消除了在依赖项跟踪系统中的一类边界情况,也使 Vue 实例能更好地配合类型检查系统工作。但与此同时在代码可维护性方面也有一点重要的考虑:data 对象就像组件状态的结构 (schema)。提前声明所有的响应式 property,可以让组件代码在未来修改或给其他开发人员阅读时更易于理解。

    展开全文
  • vue检测数据变化的注意事项 受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data ...

    vue检测数据变化的注意事项

    受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

    var vm = new Vue({
      data:{
        a:1
      }
    })
    
    // `vm.a` 是响应式的
    
    vm.b = 2
    // `vm.b` 是非响应式的
    

    对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。例如,对于:

    Vue.set(vm.someObject, 'b', 2)
    

    您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

    this.$set(this.someObject,'b',2)
    

    有时你可能需要为已有对象赋值多个新属性,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新属性不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的属性一起创建一个新的对象。

    // 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
    this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
    

    由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
    当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
    当你修改数组的长度时,例如:vm.items.length = newLength

    举个例子:

    var vm = new Vue({
      data: {
        items: ['a', 'b', 'c']
      }
    })
    vm.items[1] = 'x' // 不是响应性的
    vm.items.length = 2 // 不是响应性的
    

    为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:

    // Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
    

    你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

    vm.$set(vm.items, indexOfItem, newValue)
    

    为了解决第二类问题,你可以使用 splice:

    vm.items.splice(newLength)
    

    参考网址:https://cn.vuejs.org/v2/guide/reactivity.html

    展开全文
  • 本篇文章主要介绍了vue watch自动检测数据变化实时渲染的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Vue监听数据变化原理

    2021-04-22 11:08:21
    Vue监听数据变化原理 vue2.x版本底层使用Object.defineProperty监听数据变化数据变化后通知观察者observer 我们模拟new Vue()过程初始化一个vue的实例 const vm = new Vue_({ key: '' + Date.now(), data: ...

    Vue监听数据变化原理

    vue2.x版本底层使用Object.defineProperty监听数据变化,数据变化后通知观察者observer

    我们模拟new Vue()过程初始化一个vue的实例

    const vm = new Vue_({
        key: '' + Date.now(),
        data: function () {// 数据
            return {
                menu: {
                    home: 'home',
                    mine: 'mine'
                }
            }
        },
        watch:{// 监听变化
            "menu.home":function (newv, oldv) {
                console.log(`newv=${newv},oldv=${oldv}`)
            },
            "menu.mine": function (newv, oldv) {
                console.log(`newv=${newv},oldv=${oldv}`)
            }
        },
        methods:{
            setHomeName(name){
                console.log('name=',name)
                this.data.menu.home = name
            }
        }
    })
    

    调用vm的方法改变home的值,vm.setHomeName('这是home主页')

    上面这个方法在Vue中实际上相当于this.setHomeName('这是home主页')

    下面是Vue_的具体实现

    // Vue实例
    const Vue_ = function(props){
        const {key,data,watch,methods} = props;
        this._id = key;
        this.data = data();
        this.depen(watch);
        this.recursion(this.data)
        this.mapMethods(methods)
    }
    /**
     * 给wathc对象添加订阅
     * @param {Object} watch 
     */
    Vue_.prototype.depen = function(watch){
        for (var key in watch) {
            console.log('key=',key)
            this.observer(this._id).subscribe(key, watch[key])
        }
    }
    /**
     * 递归调用
     * @param {*} obj 
     * @param {*} path 
     */
    Vue_.prototype.recursion = function(obj,path){
        for (var key in obj) {
            this.defineReaactive(obj, key, obj[key], path)
        }
    }
    /**
     * 给对象添加getter/setter方法
     * @param {*} obj 对象
     * @param {*} key 属性名
     * @param {*} val 属性值
     * @param {*} path 属性路径
     */
    Vue_.prototype.defineReaactive = function(obj, key, val, path){
        var _self = this;
        path = `${path ? path + '.' : ''}${key}`
        if (typeof val === 'object') {
            this.recursion(val, path);
        } else {
            Object.defineProperty(obj, key, {
                set(newv) {
                    console.log(`path=${path},key=${key},newv=${newv},oldv=${val}`)
                    _self.observer(_self._id).publish(path, newv, val)
                    if (newv !== val) val = newv;
                },
                get() {
                    return val
                }
            })
        }
    }
    Vue_.prototype.mapMethods = function(methods){
        var _this = this;
        for (var key in methods){
            Vue_.prototype[key] = function(){
                return methods[key].apply(_this,arguments)
            }
        }
    }
    // 观察者
    Vue_.prototype.observer = (function () {
        var namespaces = {}, NAMESPACE = '_default'
        /**
         * 监听
         * @param {string} path 
         * @param {*} cache 
         * @param {Function} cb 
         */
        var _subsribe = function (path, cache, cb) {
            if (!cache[path]) {
                cache[path] = [];
            }
            var listeners = cache[path];
            listeners.push(cb)
        }
        /**
         * 发布订阅
         * @param {string} path 
         * @param {*} cache 
         * @param  {arguments} args 
         */
        var _publish = function (path, cache, ...args) {
            if (cache[path]) {
                var listeners = cache[path];
                listeners.forEach(function (cb) {
                    cb.apply(cb, args)
                })
            }
        }
        /**
         * 创建观察者实例
         * @param {String} namespace 
         * @returns {{subscribe, publish}} 返回一个对象
         */
        var create = function (namespace) {
            namespace = namespace || NAMESPACE;
            var listenerCache = {}
            var subscribe = function (type, cb) {
                _subsribe(type, listenerCache, cb)
            }
            var publish = function (type, ...args) {
                _publish(type, listenerCache, ...args)
            }
            return namespaces[namespace] ? namespaces[namespace] : namespaces[namespace] = { subscribe, publish }
        }
        return create;
    })();
    
    

    下图给出了Data,observer, dep, wather之间的关系
    在这里插入图片描述

    参考文献

    • 深入浅出Vue.js-第二章. [D]. 刘博文. 人民邮电出版社
    展开全文
  • vue检测不到数据变化

    千次阅读 2019-07-15 15:40:25
    1.首先先说js的数据类型 分为两种:基本数据类型和引用数据类型 对于基本数据类型的观测可以使用watch,或者computed计算...2.我们在项目中会遇到数据改变了但视图没有发生变化,例如使用computed 这是什么原因呢? 原...

    1.首先先说js的数据类型
    分为两种:基本数据类型和引用数据类型
    对于基本数据类型的观测可以使用watch,或者computed计算数据
    然而引用数据类型 数组或者对象 需要深度监听
    watch: {
    arr: {
    immediate: true,
    handler(val) {
    。。。
    }
    }
    },
    2.我们在项目中会遇到数据改变了但视图没有发生变化,例如使用computed
    这是什么原因呢?
    原因在Object.defineproperty()方法在操作数据和对象不会触发set方法所以视图不会更新
    受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。

    解决方法:1.this.$set(obj,‘b’,2)=》针对于对象
    2.生成一个新的数组在使用数组的变异方法如push,splice,等,因为数组的变异方法,也不会触发set所以会出现视图不更新

    展开全文
  • Vue中 想在路由变化的时候插入事件,需要使用到 vueRouter动态路由匹配中的响应路由参数的变化方法,提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染...
  • 这篇文章主要介绍了Vue检测屏幕变化来改变不同的charts样式实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧css中我们经常会通过媒体查询就可以完成对不同的屏幕展现不同的样式在js中我们也...
  • 本文介绍了vue watch自动检测数据变化实时渲染的方法,分享给大家,具体如下:首先确认 watch是一个对象,一定要当成对象来用。对象就有键,有值。键:就是你要监控的那个家伙,比如说$route,这个就是要监控路由的...
  • vue表格数据变化却没有刷新

    千次阅读 2020-04-01 09:54:13
    检测data的变化,修改key来刷新table <el-table :data="data" :key="tableChange" > </el-table> <script lang="ts"> import { Component, Vue, Watch } from 'vue-property-decorato...
  • 可以直接在子组件修改对象或数组,但是并不会数据改变就会引起变化检测对象变化 1、不能检测到对象属性的添加或删除 var vm = new Vue({ data:{ data111:{ a = 1 } } }) data111.a = 2;//这个可以引起变化 ...
  • vue检测对象和数组的变化

    千次阅读 2017-02-17 17:01:17
    在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部...检测对象变化1、不能检测到对象属性的添加或删除var vm = new Vue({ data:{ data111:{ a = 1 } } })d
  • 既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟DOM进行diff检测差异? 考点: Vue的变化侦测原理 前置知识: 依赖收集、虚拟DOM、响应式系统 现代前端框架有两种方式侦测变化,一种是pull一种是push ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,319
精华内容 4,527
关键字:

vue检测数据的变化

vue 订阅