Heim >Web-Frontend >js-Tutorial >Vertiefte Kenntnisse der globalen Vue-API
Kennt sich jeder mit API aus? In diesem Artikel wird hauptsächlich ein tiefgreifendes Verständnis der globalen API der offiziellen Vue-Dokumentation vorgestellt. Der Herausgeber hält sie für recht gut, daher werde ich sie jetzt mit Ihnen teilen und als Referenz verwenden. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.
Vue.extend
Die Konfigurationselementdaten müssen funktionsfähig sein, andernfalls ist die Konfiguration ungültig. Der Quellcode der Datenzusammenführungsregeln (Sie können „Vue Official Documentation – Global Configuration“ sehen) lautet wie folgt:
Übergeben Sie Daten vom Nichtfunktionstyp (die Die Daten im Bild oben sind als {a:1} konfiguriert. Wenn die Daten beim Zusammenführen von Optionen nicht vom Funktionstyp sind, gibt die Entwicklungsversion eine Warnung aus und gibt dann direkt parentVal zurück, was bedeutet, dass die von Extend übergebene Datenoption vorhanden ist ignoriert.
Wir wissen, dass Daten bei der Instanziierung von Vue ein Objekt sein können. Sind die Zusammenführungsregeln hier nicht universell? Beachten Sie, dass es bei der Instanziierung ein if(!vm)-Urteil gibt, das sich von Vue.extend unterscheidet. Tatsächlich wird dies auch in den folgenden Kommentaren erläutert (bei einer Vue.extend-Zusammenführung sollten beide Funktionen vorliegen). ), weshalb die offizielle Dokumentation besagt, dass Daten ein Sonderfall sind.
Darüber hinaus ist die im offiziellen Dokument erwähnte „Unterklasse“ darauf zurückzuführen, dass Vue.extend eine Funktion zurückgibt, die Vue „erbt“. Die Quellcodestruktur ist wie folgt:
Vue.extend = function (extendOptions) { //*** var Super = this; var SuperId = Super.cid; //*** var Sub = function VueComponent(options) { this._init(options); }; Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub; //*** return Sub };
Vue.nextTick
Da man Vue nutzt, muss man natürlich datengetrieben denken. „Datengesteuert“ bedeutet, dass dom nicht direkt bedient werden kann. Die Anweisungen „binden“ die Daten an dom und sind auch praktischer.
Wenn der Browser Promise unterstützt oder die Promise-Bibliothek verwendet (die nach außen zugängliche Bibliothek muss jedoch Promise heißen, da die Beurteilung im Quellcode vom Typ Promise ist! == 'undefiniert') , nextTick gibt das Promise-Objekt zurück.
Vue.nextTick().then(() => { // do sth })
Der Rückruf für Vue zum Ausführen von nextTick verwendet die Aufrufmethode cb.call(ctx); ctx ist die aktuelle Vue-Instanz, also kann es sein Wird direkt im Callback verwendet. Dadurch wird die Konfiguration der Instanz aufgerufen.
nextTick kann einfach so verstanden werden, dass der Rückruf am Ende zur Ausführung platziert wird. Wenn Promise und MutationObserver derzeit nicht im Quellcode unterstützt werden, wird die setTimeout-Methode verwendet, um den Rückruf auszuführen die Ausführung von Code verzögern.
if (typeof Promise !== 'undefined' && isNative(Promise)) { } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = function () { setTimeout(nextTickHandler, 0); }; }
Nehmen wir ein Beispiel:
<p id="app"> <p ref="dom">{{a}}</p> </p> new Vue({ el: '#app', data: { a: 1 }, mounted: function name(params) { console.log('start'); this.$nextTick(function () { console.log('beforeChange', this.$refs.dom.textContent) }) this.a = 2; console.log('change'); this.$nextTick(function () { console.log('afterChange', this.$refs.dom.textContent) }) console.log('end'); } }) // 控制台依次打印 // start // change // end // beforeChange 1 // afterChange 2
Das kann sein Ein wenig verwirrt. Warum wird beforeChange 1 statt 2 ausgegeben? Dies liegt daran, dass das hinter this.a=2 ausgelöste Dom-Update auch nextTick verwendet. Die tatsächliche Ausführungsreihenfolge des obigen Codes ist: beforeChange> ;afterChange.
Vue.set
Vue.set( Ziel, Schlüssel, Wert), das Ziel darf keine Vue-Instanz oder das Stammdatenobjekt einer Vue-Instanz sein, weil es im Quellcode erfolgt. Es wird folgendes Urteil gefällt:
var ob = (target).__ob__; if (target._isVue || (ob && ob.vmCount)) { "development" !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.' ); return val }
target._isVue verhindert das Hinzufügen von Attributen zur Vue-Instanz, ob && ob. vmCount verhindert, dass das Stammdatenobjekt der Vue-Instanz Attribute hinzufügt.
Vue.delete
Wenn Vue den Löschvorgang erkennen kann, wird diese API nicht angezeigt. Wenn Sie zum Löschen des $data-Attributs delete verwenden müssen, verwenden Sie Vue.delete, andernfalls wird die Dom-Aktualisierung nicht ausgelöst.
Wie bei Vue.set kann das Ziel von Vue.delete(target, key) keine Vue-Instanz oder das Stammdatenobjekt einer Vue-Instanz sein. Die Blockierungsmethode im Quellcode ist dieselbe wie bei Vue.set.
Wenn das Ziel in Version 2.2.0+ ein Array ist, ist der Schlüssel der Array-Index. Da Vue.delete tatsächlich Splice zum Löschen eines Arrays verwendet, kann zwar mit delete ein Array gelöscht werden, die Position ist jedoch immer noch vorhanden und kann nicht als echte Löschung betrachtet werden.
var a = [1, 2, 3]; delete a[0]; console.log(a); // [undefined, 2, 3]
Vue.use
Vue.use Der Quellcode ist relativ einfach und kann in gepostet werden voll.
Vue.use = function (plugin) { var installedPlugins = (this._installedPlugins || (this._installedPlugins = [])); if (installedPlugins.indexOf(plugin) > -1) { return this } // additional parameters var args = toArray(arguments, 1); args.unshift(this); if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args); } else if (typeof plugin === 'function') { plugin.apply(null, args); } installedPlugins.push(plugin); return this };
Die installierten Plug-Ins werden in „installedPlugins“ abgelegt. Verwenden Sie vor der Installation des Plug-ins „installedPlugins.indexOf(plugin)“, um festzustellen, ob das Plug-in installiert ist -in wurde installiert, wodurch verhindert wird, dass dasselbe Registrierungs-Plugin mehrmals verwendet wird.
Der Plug-in-Typ ist Objekt und das Installationsattribut muss angegeben werden, um das Plug-in zu installieren (typeofplugin.install === 'function'). verwendet „plugin.install.apply(plugin, args);“ und greift daher auf andere Eigenschaften des Objekts zu. Die Argumente hier sind die Parameter außer dem Plugin, die von Vue (args.unshift(this);) und Vue.use (toArray(arguments, 1) übergeben werden, 1 bedeutet Abfangen ausgehend von arguments[1]).
Vue.use({ a: 1, install: function (Vue) { console.log(this.a) // 1 console.log(arguments) // [function Vue(options),"a", "b", "c"] } }, 'a', 'b', 'c')
Der Plug-in-Typ ist Funktion, und die Installation ruft plug-in.apply(null, args); auf, sodass im strikten Modus das Plug-in Im Laufzeitkontext ist dies null , der nicht-strikte Modus ist Window.
'use strict' Vue.use(function plugin() { console.log(this) // null console.log(arguments) // [function Vue(options),"a", "b", "c"] }, 'a', 'b', 'c')
Vue.compile
和众多 JS 模板引擎的原理一样,预先会把模板转化成一个 render 函数,Vue.compile 就是来完成这个工作的,目标是将模板(template 或 el)转化成 render 函数。
Vue.compile 返回了{render:Function,staticRenderFns:Array},render 可直接应用于 Vue 的配置项 render,而 staticRenderFns 是怎么来的,而且按照官网的例子,Vue 还有个隐藏的配置项 staticRenderFns,先来个例子看看。
var compiled = Vue.compile( '<p>' + '<header><h1>no data binding</h1></header>' + '<section>{{prop}}</section>' + '</p>' ) console.log(compiled.render.toString()) console.log(compiled.staticRenderFns.toString()) // render function anonymous() { with(this) { return _c('p', [_m(0), _c('section', [_v(_s(prop))])]) } } // staticRenderFns function anonymous() { with(this) { return _c('header', [_c('h1', [_v("no data binding")])]) } }
原来没有和数据绑定的 dom 会放到 staticRenderFns 中,然后在 render 中以_m(0)来调用。但是并不尽然,比如上述模板去掉4a249f0d628e2318394fd9b75b4636b1,staticRenderFns 长度为 0,header 直接放到了 render 函数中。
function anonymous() { with(this) { return _c('p', [_c('header', [_v("no data binding")]), _c('section', [_v(_s(prop))])]) } }
Vue.compile 对应的源码比较复杂,上述渲染 1aa9e5d373740b65a0cc8f0a02150c53 没有放到 staticRenderFns 对应源码的核心判断如下:
// For a node to qualify as a static root, it should have children that // are not just static text. Otherwise the cost of hoisting out will // outweigh the benefits and it's better off to just always render it fresh. if (node.static && node.children.length && !( node.children.length === 1 && node.children[0].type === 3 )) { node.staticRoot = true; return } else { node.staticRoot = false; }
1aa9e5d373740b65a0cc8f0a02150c53 不符判断条件 !(node.children.length === 1 && node.children[0].type === 3), 1aa9e5d373740b65a0cc8f0a02150c53 有一个子节点 TextNode(nodeType=3)。 注释也说明了一个 node 符合静态根节点的条件。
另外官网说明了此方法只在独立构建时有效,什么是独立构建?这个官网做了详细的介绍,不再赘述。对应官网地址:对不同构建版本的解释。
仔细观察编译后的 render 方法,和我们自己写的 render 方法有很大区别。但是仍然可以直接配置到 render 配置选项上。那么里面的那些 _c()、_m() 、_v()、_s() 能调用?随便看一个 Vue 的实例的 __proto__ 就会发现:
// internal render helpers. // these are exposed on the instance prototype to reduce generated render // code size. Vue.prototype._o = markOnce; Vue.prototype._n = toNumber; Vue.prototype._s = toString; Vue.prototype._l = renderList; Vue.prototype._t = renderSlot; Vue.prototype._q = looseEqual; Vue.prototype._i = looseIndexOf; Vue.prototype._m = renderStatic; Vue.prototype._f = resolveFilter; Vue.prototype._k = checkKeyCodes; Vue.prototype._b = bindObjectProps; Vue.prototype._v = createTextVNode; Vue.prototype._e = createEmptyVNode; Vue.prototype._u = resolveScopedSlots; Vue.prototype._g = bindObjectListeners;
正如注释所说,这些方法是为了减少生成的 render 函数的体积。
全局 API 还剩 directive、filter、component、mixin,这几个比较类似,而且都对应着配置项,会在「选项」中再详细介绍。
相关推荐:
Das obige ist der detaillierte Inhalt vonVertiefte Kenntnisse der globalen Vue-API. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!