[Vue] v-model バインドされたオブジェクトがリアルタイムで更新されない

做棵大树
リリース: 2020-07-14 09:42:01
オリジナル
170 人が閲覧しました

元のリンク: 大きなツリーを作る

最近参加したプロジェクトでは、フロントエンドでvue.jsフレームワークを使用しており、その過程で動的のプロパティの追加が必要な機能がありました。バインドされたオブジェクトに。しかし、実際のアプリケーションでは、オブジェクトに属性を追加した後、そのオブジェクトにバインドされているコンポーネントのコンテンツが変更されないという問題が発生します。コンポーネントのコンテンツが変更されたコンテンツに変更される前に、コンポーネントを再度更新する必要があります。

最初は、属性が正常に追加されなかったためだと思いました。私の印象では、v-modelは双方向バインドされており、非更新状態にはならないからです。 Devtools でモニタリングを確認したところ、対応するオブジェクトに指定された属性が追加されていることがわかりました。

そこで、公式ドキュメントをチェックしに行ったところ、公式の説明を見つけました: Vue.js が変更を追跡する方法

公式説明

通常の JavaScript オブジェクトを data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty として Vue インスタンスに渡す場合、これは ES5 の機能であり、Vue が IE8 以前のブラウザをサポートしていないのはこのためです。

各コンポーネント インスタンスは watcher インスタンスに対応し、コンポーネントのレンダリング プロセス中に「タッチされた」データ プロパティを依存関係として記録します。 その後、依存関係のセッターがトリガーされると、ウォッチャーに通知され、関連するコンポーネントが再レンダリングされます。

[Vue] v-model バインドされたオブジェクトがリアルタイムで更新されない
公式説明凡例

変更の検出に関する注意事項

JavaScriptの制限により、Vueは配列やオブジェクトの変更を検出することができません。それでも、これらの制限を回避して応答性を維持する方法はあります。

オブジェクト

の場合、Vueはプロパティの追加または削除を検出できません。 Vue はインスタンスの初期化時にプロパティのゲッター/セッター変換を実行するため、プロパティは data は、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</code > インスタンス メソッド、これもグローバル rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;">Vue.set</ code> メソッド エイリアス: <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 22px;">rrreee <span class="prefix" style="display: none;"> 場合によっては、<code style="font-size: 14px; word-wrap:break-word;padding:2px 4px; border- を使用するなど、既存のオブジェクトに複数の新しいプロパティを割り当てる必要がある場合があります。半径: 4px; マージン: 0 2px; 背景色: rgba(27,31,35,.05); 演算子 Mono、Consolas、Menlo、ワードブレイク: ブレーク-all;">オブジェクト. assign() または _.extend( )</コード>。ただし、この方法でオブジェクトに追加された新しいプロパティは更新をトリガーしません。この場合、元のオブジェクトと混合するオブジェクトのプロパティを使用して新しいオブジェクトを作成する必要があります。 </span>rrreee<span class="content">これは、公式ソリューション<code style="font-size: 14px; word-wrap: Break-word;padding: 2px 4px; border-radius: 4px; margin : 0 2px;" を使用したオブジェクト割り当ての解決策です。 color: #1e6bb8; 背景色: rgba(27,31,35,.05); フォントファミリー: 演算子 Mono、Consolas、Monaco、monospace;"> this.$set (object, key, value) はリアルタイム更新効果を実現します。同時に、配列やその他の状況については、残りの公式文書

を確認できます。なぜこれが起こっているのでしょうか?

🎜🎜公式が 🎜 と言っているように、「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 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
1
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!