序文コア機能のデフォルトの組み込みディレクティブ (v-model および v-show) に加えて、Vue ではカスタム ディレクティブを登録することもできます。 公式サイトの紹介は比較的抽象的で、非常に壮大に思えます。カスタム命令についての私の個人的な理解は、カスタム命令が一部の DOM 要素またはコンポーネントに作用する場合、要素は最初にレンダリングされるとき、親ノードに挿入されるとき、更新されるとき、またはアンバインドされるときに、いくつかの特定の操作 (フック関数 ()) を実行できるということです。 カスタムディレクティブを登録する方法は 2 つあります。1 つはグローバル登録で、Vue.directive (ディレクティブ名、構成パラメータ) を使用して登録します。登録後は、すべての Vue インスタンスで使用できます。もう 1 つはローカル登録です。Vue インスタンスを作成するときに、directives 属性を通じてローカルディレクティブが作成されます。ローカルカスタムディレクティブは、現在の Vue インスタンスでのみ使用できます。 カスタム命令は、次のフック関数にバインドできます。
各フック関数には、el (対応する DOM ノード参照)、binding (命令に関する拡張情報、オブジェクト)、vnode (ノードに対応する仮想 VNode)、oldVnode (以前の VNode、update フックと componentUpdated フックでのみ使用可能) の 4 つのパラメータがあります。 バインド フック関数が実行されると、DOM 要素はレンダリングされますが、親要素には挿入されません。次に例を示します。 <!DOCTYPE html> <html lang="ja"> <ヘッド> <メタ文字セット="UTF-8"> <title>ドキュメント</title> <script src="vue.js"></script> </head> <本文> <div id="d"><input type="" name="" v-focus></div> <スクリプト> Vue.directive('focus', { bind:function(el){console.log(el.parentElement);}, // 挿入された親ノードを出力します: function (el) {console.log(el.parentElement);el.focus()} // 親ノードを出力し、現在の要素にフォーカスを当てます }) var app = new Vue({el:"#d"}) </スクリプト> </本文> </html> 出力は次のようになります。 入力要素が自動的にフォーカスを取得し、コンソール出力が次のようになっていることがわかります。 bind() フックの場合、Vue は bind() フックを実行した後にのみ現在の要素を親要素の子ノードに挿入するため、その親ノードを取得できないことがわかります。 ソースコード分析processAttrs() 関数は、テンプレートを解析して DOM を AST オブジェクトに変換するときに次のように実行されます。 function processAttrs (el) { //Vue 属性を解析 var list = el.attrsList; var i、l、名前、rawName、値、修飾子、isProp; for (i = 0, l = list.length; i < l; i++) { //各属性を走査します name = rawName = list[i].name; 値 = リスト[i].値; if (dirRE.test(name)) { //属性がv-、@、または:で始まる場合、これはVue内部ディレクティブであることを意味します //要素を動的としてマークします el.hasBindings = true; // 修飾子 修飾子 = parseModifiers(名前); if (修飾子) { name = name.replace(modifierRE, ''); } if (bindRE.test(name)) { // v-bind //bindRD は /^:|^v-bind:/ に等しい、つまり属性が v-bind 命令 /*v-bind 分岐*/ の場合 } else if (onRE.test(name)) { // v-on /* v-on の分岐 */ } else { // 通常のディレクティブ name = name.replace(dirRE, ''); //命令のプレフィックスを削除します。たとえば、v-show は実行後に show と同じになります。 // 引数を解析する var argMatch = name.match(argRE); var arg = argMatch && argMatch[1]; if (引数) { name = name.slice(0, -(arg.length + 1)); } addDirective(el, name, rawName, value, arg, modifiers); //addDirective を実行して、el にディレクティブ属性を追加します。if ("development" !== 'production' && name === 'model') { エイリアスモデルをチェックします(el、値); } } } それ以外 { /*非Vueディレクティブブランチ*/ } } } addDirective は、次のように、命令情報を保存するディレクティブ属性を AST オブジェクトに追加します。 function addDirective ( // 6561行目は命令に関連しています。ASTオブジェクトelに命令elの情報を持つディレクティブ属性を追加します。 名前、 生の名前、 価値、 引数、 修飾語 ){ (el.directives || (el.directives = [])).push({ name: name, rawName: rawName, value: value, arg: arg, modifiers: modifiers }); el.plain = false; } ここで例の p 要素を実行すると、対応する AST オブジェクトは次のようになります。 次に、generate が rendre 関数を生成すると、次のように genDirectives() 関数が実行され、AST がレンダリング関数に変換されます。 (this){return _c('div',{attrs:{"id":"d"}},[_c('input',{directives:[{name:"focus",rawName:"v-focus"}],attrs:{"type":"","name":""}})])} 最後に、レンダリングが完了すると、次のようにディレクティブ モジュールの create フック関数が実行されます。 var directives = { // 行 6173 ディレクティブ module create: updateDirectives, // DOM 作成後のフック update: updateDirectives, 破棄: 関数 unbindDirectives (vnode) { ディレクティブを更新します(vnode、空のノード)。 } } function updateDirectives (oldVnode, vnode) { //行 6181 oldVnode: 古い Vnode、vnode は更新時にのみ使用可能: 新しい VNode if (oldVnode.data.directives || vnode.data.directives) { _update(古いVnode、vnode); } } _updat は、次のように処理命令を初期化および更新するために使用されます。 function _update (oldVnode, vnode) { // 6187 行目の初期化/更新命令 var isCreate = oldVnode === emptyNode; // 初期化ですか var isDestroy = vnode === emptyNode; var oldDirs = normalizeDirectives$1(oldVnode.data.directives、oldVnode.context); var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context); //パラメータを正規化するためにnormalizeDirectives$1()関数を呼び出します var dirsWithInsert = []; var dirsWithPostpatch = []; var キー、oldDir、dir; for (key in newDirs) { //newDirsを走査する oldDir = oldDirs[key]; // 古い方のキーディレクティブ情報Vnodedir = newDirs[key]; // 古い方のキーディレクティブ情報vnodeif (!oldDir) { // oldDir が存在しない場合は新しいディレクティブです // 新しいディレクティブ、bind callHook$1(dir, 'bind', vnode, oldVnode); //callHook$1() 関数を呼び出します。パラメータ 2 は bind です。つまり、v-focus 命令の bind 関数を実行します。if (dir.def && dir.def.inserted) { //挿入されたフック関数が定義されている場合 dirsWithInsert.push(dir); //それを dirsWithInsert 配列に保存します} } それ以外 { // 既存のディレクティブを更新 dir.oldValue = oldDir.value; callHook$1(dir, 'update', vnode, oldVnode); dir.def がコンポーネント更新された場合 dirsWithPostpatch.push(dir); } } } if (dirsWithInsert.length) { // dirsWithInsertが存在する場合(つまり、挿入されたフック関数がバインドされている場合) var callInsert = function () { // dirsWithInsert 内の各関数を実行する callInsert 関数を定義します for (var i = 0; i < dirsWithInsert.length; i++) { callHook$1(dirsWithInsert[i], '挿入済み', vnode, oldVnode); } }; if (isCreate) { // 初期化されている場合 mergeVNodeHook(vnode, 'insert', callInsert); // mergeVNodeHook() 関数を呼び出す } else { 挿入() を呼び出します。 } } (dirsWithPostpatch.length)の場合{ mergeVNodeHook(vnode, 'postpatch', 関数() { (var i = 0; i < dirsWithPostpatch.length; i++) { callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode); } }); } 作成する場合 for (キー in oldDirs) { if (!newDirs[キー]) { // 存在しないので、バインドを解除します callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy); } } } } 作者: Great Desert QQ: 22969969 バインド フック関数の場合は直接実行されますが、挿入されたフック関数の場合は関数が dirsWithInsert 配列に保存され、callInsert 関数が定義されます。関数はスコープを通じて dirsWithInsert 変数にアクセスし、変数をトラバースして挿入された各フック関数を順番に実行します。 mergeVNodeHook() フック関数は、対応する Vnode のデータにフック属性として挿入を保存します。Vnode が親ノードに挿入されると、次のようにフックが呼び出されます。 function mergeVNodeHook (def, hookKey, hook) { // 2074行目はVNodeフックをマージします。関数def: VNode hookKey: (イベント名、例: insert) hook: コールバック関数if (def instanceof VNode) { // defがVNodeの場合 def = def.data.hook || (def.data.hook = {}); // VNode.data.hook にリセットします。VNode.data.hook が存在しない場合は、空のオブジェクトに初期化します。注: 通常のノードでは VNode.data.hook は存在しません。 } var 呼び出し元; var oldHook = def[hookKey]; 関数 wrappHook() { hook.apply(this, arguments); // 最初にフック関数を実行します // 重要: マージされたフックを削除して、1 回だけ呼び出されるようにします // メモリリークを防ぐ remove(invoker.fns, wrappHook); //invoker.fns から wrappHook を削除して、パッケージが 1 回だけ実行されるようにします} if (isUndef(oldHook)) { //oldHookが存在しない場合、つまりhookKeyフック関数が以前に定義されていない場合 //既存のフックはありません invoker = createFnInvoker([wrappedHook]); //createFnInvoker() を直接呼び出して、実行されるコールバック関数をパラメータとするクロージャ関数を返します} else { /* イスタンブールは無視します */ if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { // すでにマージされた呼び出し元 呼び出し元 = oldHook; 呼び出し元.fns.push(ラップされたフック); } それ以外 { // 既存のプレーンフック 呼び出し側 = createFnInvoker([oldHook, wrappHook]); } } 呼び出し側がマージされる = true; def[hookKey] = invoker; // defのhookKeyプロパティを新しいinvokerを指すように設定する } createFnInvoker は v-on 命令に対応する関数です。同じ API を使用します。実行後、次のように、input に対応する VNode.data.hook にinvoker を挿入します。 最後に、VNode が親ノードに挿入された後、invokeCreateHooks() 関数が実行されます。この関数は VNode.hook.insert を走査し、各関数を順番に実行し、カスタム定義の挿入フック関数を実行します。 要約するVue.js ソースコード解析のカスタム手順に関するこの記事はこれで終わりです。より関連性の高い Vue.js カスタム手順については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: MySQLマスタースレーブデータベース構築方法の詳細な説明
>>: nginx + fastcgi を使用して画像認識サーバーを実装する
目次1. 実施計画の概要2. 実行計画の実践id:選択タイプ:テーブル:タイプ:可能なキー:鍵:キー...
[ Tomcat8 の Linux インストール ] Tomcat をアンインストールする - まず...
皆さんの時間は貴重だと承知しているので、プロセス コマンドを直接書き留めておきます。設定できます。原...
JavaScript DOM を読み終えた後、解釈型 JavaScript スクリプト言語に対する...
MySQL で concat 関数を使用する方法: CONCAT(文字列1、文字列2、…)戻り値は、...
目次1. オブジェクト1.1 オブジェクトとは何ですか? 1.2 なぜオブジェクトが必要なのか? 2...
nginx は弊社で最もよく使用されるサーバーで、コンテンツ配信やリバース プロキシによく使用されま...
目次作成機能配列プロトタイプの削減Array.prototype.reduceRightパイプ関数作...
1. 前提条件1. プロジェクトが展開されました2. Dockerはすでにインストールされている2...
init_connectの役割init_connect は通常、接続が来たときに、自動コミットを 0...
MySQL 開発チームは、2019 年 10 月 14 日に MySQL 8.0.18 GA バージ...
3 つの方法を使用する簡単な例は次のとおりです。インラインスタイル: <!doctypehtm...
【質問】 INSERT 文は最も一般的な SQL 文の 1 つです。最近、MySQL サーバーが同時...
この記事は主にMySQLデータ移行方法とツールの分析を紹介します。サンプルコードを通じて詳細に紹介さ...
XMeter API は、以下のサービスを含む、JMeter に基づくワンストップのオンライン イン...