>  기사  >  웹 프론트엔드  >  [Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.

[Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.

做棵大树
做棵大树원래의
2020-07-13 23:04:15129검색

원본 링크: Build a big tree

최근 참여한 프로젝트에서 프런트엔드에 vue.js 프레임워크를 사용했는데, 그 과정에서 동적속성을 추가해야 하는 기능이 있었습니다. 바인딩된 개체에. 그러나 실제 응용에서는 문제가 발생합니다. 객체에 속성을 추가한 후에도 객체에 바인딩된 구성 요소의 내용이 변경되지 않은 경우 해당 내용이 변경된 내용으로 변경되기 전에 구성 요소를 다시 새로 고쳐야 합니다.

처음에는 속성이 성공적으로 추가되지 않았기 때문이라고 생각했습니다. 내 인상으로는 v-model가 양방향 바인딩이고 업데이트되지 않은 상태가 아니기 때문입니다. Devtools에서 모니터링을 확인한 후 해당 개체에 지정된 속성이 추가된 것을 발견했습니다.

그래서 공식 문서를 확인하고 공식 설명을 찾았습니다: Vue.js가 변경 사항을 추적하는 방법

공식 설명

일반적인 JavaScript 객체를 Vue 인스턴스에 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty로 전달하면 ES5의 기능으로 인해 Vue가 IE8 이하 브라우저를 지원하지 않습니다.

각 구성 요소 인스턴스는 구성 요소 렌더링 프로세스 중에 "접촉된" 데이터 속성을 종속성으로 기록하는 watcher 인스턴스에 해당합니다. 나중에 종속성의 setter가 트리거되면 watcher에 알림이 전달되어 관련 구성 요소가 다시 렌더링됩니다.

[Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.
공식 설명 범례

변경 사항 감지에 대한 참고 사항

JavaScript 제한으로 인해 Vue는 배열과 객체의 변경 사항을 감지할 수 없습니다. 그럼에도 불구하고 이러한 제한 사항을 피하고 대응력을 유지할 수 있는 방법이 있습니다.

객체의 경우

Vue는 속성 추가 또는 제거를 감지할 수 없습니다 . Vue는 인스턴스를 초기화할 때 속성에 대해 getter/setter 변환을 수행하므로 속성은 데이터는 Vue가 반응형으로 변환하기 위해 개체에 존재합니다. 예: data 对象上存在才能让 Vue 将它转换为响应式的。例如:

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">var vm = new Vue({<br/>  data:{<br/>    a:1<br/>  }<br/>})<br/><br/>// `vm.a` 是响应式的<br/><br/>vm.b = 2<br/>// `vm.b` 是非响应式的<br/></code>

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

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">Vue.set(vm.someObject, <span class="hljs-string" style="color: #D69D85; line-height: 26px;">&#39;b&#39;</span>, 2)<br/></code>

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

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">this.<span class="hljs-variable" style="color: #BD63C5; line-height: 26px;">$set</span>(this.someObject,<span class="hljs-string" style="color: #D69D85; line-height: 26px;">&#39;b&#39;</span>,2)<br/></code>

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

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;">// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`<br/>this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })<br/></code>

这是对于对象赋值的解决方式,在采用了官方的解决方案 this.$set(object, key, value)

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;"><span class="hljs-keyword" style="color: #569CD6; line-height: 26px;">function</span> Vue(obj){<br/>    obj.data.keys().forEach((prop, index) => {<br/>      Object.defineProperty(obj.data, prop, {<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">set</span></span>(){<br/>          //可以在此处进行事件监听<br/>        },<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">get</span></span>(){<br/>    <br/>        }<br/>      })<br/>    })<br/>    <span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> obj;<br/> }<br/></code>
이미 생성된 인스턴스의 경우 Vue는 루트 수준 반응 속성의 동적 추가를 허용하지 않습니다. 그러나 Vue.set(object, propertyName, value) 메서드 중첩된 개체에 반응형 속성을 추가합니다. 예: rrreee

vm.$set 인스턴스 방법, 이것은 또한 전역 rgba(27,31,35,.05); 글꼴 계열: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all;">Vue.set code> 메소드 별명:

rrreee

왜 이런 일이 발생하는지 확인할 수 있습니다.

🎜🎜 관계자가 말했듯이 🎜 "JavaScript 제한으로 인해 Vue 🎜는 배열 및 객체의 변경 사항 🎜을 감지할 수 없습니다. 그런데 왜 그럴까요?" 🎜

借用 Segmentfault UKer 的回答:

ECMAScript中有两种属性:数据属性访问器属性; 数据属性的描述符为:Configurable,Enumerable,Writable,Value; 访问器属性的描述符为:Configurable, Enumerable,set,get。

当我们使用new Vue(obj),其内部发生了大体如下代码的转换,即,将数据属性转换为了访问器属性

<span style="display: block; background: url(https://imgkr.cn-bj.ufileos.com/97e4eed2-a992-4976-acf0-ccb6fb34d308.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #1E1E1E; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #DCDCDC; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #1E1E1E; border-radius: 5px;"><span class="hljs-keyword" style="color: #569CD6; line-height: 26px;">function</span> Vue(obj){<br/>    obj.data.keys().forEach((prop, index) => {<br/>      Object.defineProperty(obj.data, prop, {<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">set</span></span>(){<br/>          //可以在此处进行事件监听<br/>        },<br/>        <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">get</span></span>(){<br/>    <br/>        }<br/>      })<br/>    })<br/>    <span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> obj;<br/> }<br/></code>

但是当我们后面再次使用普通的赋值,仅仅是赋值了一个数据属性的,这个属性是不会具有访问器属性的事件监听功能的。

至此,v-model 绑定数据不实时更新的问题方才得到了解决。


[Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.
[Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.

위 내용은 [Vue] v-model 바인딩된 개체가 실시간으로 업데이트되지 않습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.