이번에는 Vue의 배열 변경 감지 문제를 가져오겠습니다. Vue의 배열 변경 감지에 대한 주의 사항은 무엇입니까?
rreee여기서 구현 목적은 매우 명확합니다---클릭하면 li가 있는지 감지하고 싶습니다. 물론 존재하지 않으므로 값을 1로 설정합니다. 다시 클릭하면 숫자가 누적됩니다.
그러나 발생하는 문제는 클릭 후 뷰 레이어에서 숫자가 업데이트되지 않고 콘솔 인쇄를 통해 데이터가 실제로 업데이트되는 것으로 확인되지만 뷰 레이어에서는 이를 제때 감지하지 못한다는 것입니다. 그리고 제가 생각한 것은 Vue가 양방향 데이터 바인딩을 구현하는데 왜 모델 레이어가 변경된 후 뷰 레이어에서 업데이트되지 않습니까? 먼저 이것이 배열 문제인지 고려하여 다음 예제를 테스트했습니다.
예시 2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script> <style> li:hover { cursor: pointer; } </style> </head> <body> <p class="wrap"> <ul> <li v-for="item,index in items" v-on:click="handle(index)"> <span>{{item.name}}</span> <span>{{numbers[index]}}</span> </li> </ul> </p> <script> var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // WHY: 更新数据,view层未渲染,但通过console这个数组可以发现数据确实更新了 if (typeof(this.numbers[index]) === "undefined" ) { this.numbers[index] = 1; } else { this.numbers[index]++; } } } }); </script> </body> </html>
이때 다시 테스트를 해보니 여기의 모델 레이어가 변경되면 뷰 레이어가 적시에 효과적으로 업데이트될 수 있다는 것을 발견했습니다.
가장 중요한 문장은 개체가 반응형이라면
property도 생성된 후 반응형인지 확인하고 뷰 업데이트를 트리거하는 것입니다. 이 방법은 주로 Vue가 속성이 감지되지 않는다는 제한을 피하기 위해 사용됩니다. . 그러면 어떤 상황에서 Vue가 속성이 추가되었는지 감지하지 못할 수 있나요? 참조 링크에 따르면 문서에서 좋은 설명을 보았습니다 --- 심층 반응 원리
먼저 Vue가 데이터의 양방향 바인딩을 구현하는 방법을 이해해야 합니다!
일반
JavaScript객체를 Vue 인스턴스의 데이터 옵션에 전달합니다. Vue는 이 객체의 모든 속성을 반복하여 사용합니다. Object.defineProperty는 이러한 모든 속성을 getter/setter로 변환합니다. Object.defineProperty는 ES5는 기능을 지원하지만 심을 수는 없습니다. 이것이 바로 Vue가 IE8 이하 브라우저를 지원하지 않는 이유입니다. 지식 보충 자료:
접근자 속성에는 데이터 값이 포함되어 있지 않습니다. getter 및 setter 함수 쌍이 포함되어 있습니다(이 두 함수는 필수가 아닙니다). 접근자 속성을 읽으면 유효한 값을 반환하는 getter 함수가 호출되고, 접근자 속성이 작성되면 setter 함수가 호출되고 새 값이 전달됩니다. 데이터를 처리합니다.
접근자 속성은 직접 정의할 수 없으며 Object.defineProperty()를 사용하여 정의해야 합니다.
예는 다음과 같습니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script> <style> li:hover { cursor: pointer; } </style> </head> <body> <p class="wrap"> <ul> <li v-for="item,index in items" v-on:click="handle(index)"> <span>{{item.name}}</span> <span>{{numbers[index]}}</span> </li> </ul> </p> <script> var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // 不是数组,这里更新数据就可以直接在view层渲染 this.items[index].name += " success"; } } }); </script> </body> </html>
이 예는 접근자 속성에 대한 좋은 이해를 제공해야 합니다.
따라서 객체 아래의 접근자 속성 값이 변경되면(Vue는 앞서 언급한 대로 속성을 접근자 속성으로 변환함) set 함수가 호출되고 Vue는 이 set 함수를 통해 변경 사항을 추적하고 관련 함수를 호출할 수 있습니다. 뷰를 업데이트합니다.
각 구성 요소 인스턴스에는 구성 요소 렌더링 프로세스 중에 속성을 종속성으로 기록하는 해당 감시자 인스턴스 개체가 있습니다. 나중에 종속성 설정자가 호출되면 감시자에게 다시 계산하라는 알림이 전달되어 관련 구성 요소가 업데이트됩니다. 즉, 렌더링 프로세스 중에 객체 속성의 getter 함수가 호출되고, getter 함수는 이를 종속성으로 선언하도록 water 객체에 알립니다. 객체 속성이 변경되면 setter 함수가 이를 수행합니다. 감시자에게 알리기 위해 호출되며 감시자는 업데이트를 완료하기 위해 구성 요소를 다시 렌더링합니다.
좋아요! 이제 원리를 알았으니 이전 배열 문제가 발생한 이유를 더 이해할 수 있습니다!
변경 감지 문제
최신 JavaScript 브라우저의 한계로 인해 실제로는 주로 Object.observe()입니다. 메소드 지원이 좋지 않으며 Vue는 객체 추가 또는 삭제를 감지할 수 없습니다. 그러나 Vue는 인스턴스를 초기화할 때 속성에 대해 setter/getter 변환 프로세스를 수행하므로 Vue가 변환하려면 속성이 처음부터 객체에 있어야 합니다.
所以对于前面的例子就不能理解了 --- 数组中index都可以看做是属性,当我们添加属性并赋值时,Vue并不能检测到对象中属性的添加或者删除,但是其的确是添加或删除了,故我们可以通过console看到变化,所以就没有办法做到响应式; 而在第二个例子中,我们是在已有的属性的基础上进行修改的,这些属性是在最开始就被Vue初始化实例时执行了setter/getter的转化过程,所以说他们的修改是有效的,model的数据可以实时的在view层中得到相应。
补充知识: 什么是 Object.observe() ?
在介绍之前,不得不残忍的说,尽管这个方法可以在某些浏览器上运行,但事实是这个方法已经废弃!
概述: 此方法用于异步地监视一个对象的修改。当对象的属性被修改时,方法的回调函数会提供一个有序的修改流,然而这个接口已经从各大浏览器移除,可以使用通用的proxy 对象。
方法:
Object.observe(obj, callback[, acceptList])
其中obj就是被监控的对象, callback是一个回调函数,其中的参数包括changes和acceptList,
changes一个数组,其中包含的每一个对象代表一个修改行为。每个修改行为的对象包含:
name: 被修改的属性名称。
acceptList在给定对象上给定回调中要监视的变化类型列表。如果省略, ["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"] 将会被使用。
var obj = { foo: 0, bar: 1 }; Object.observe(obj, function(changes) { console.log(changes); }); obj.baz = 2; // [{name: 'baz', object: <obj>, type: 'add'}] obj.foo = 'hello'; // [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}] delete obj.baz; // [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 Vue의 배열 변경 감지 문제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!