序文
この記事は[フロントエンド辞書]シリーズの13番目の記事です。次の9つの記事ではVueに焦点を当てます。これらの9つの記事がVueの理解を深めることを願っています。もちろん、これらの記事の前提は、デフォルトでVueの特定の基盤があることです。基本的な知識がない場合は、最初に公式ドキュメントを読むことをお勧めします。
最初の記事では、VueとVuexのソースコードの一部を組み合わせて、VuexをVueライフサイクルに注入するプロセスを説明します。
ソースコードに関しては、思ったほど難しくはありません。これは、通常ビジネスコードを作成するのとほぼ同じで、すべてメソッド呼び出しです。ただし、ソースコードの呼び出しツリーははるかに複雑になります。
Vuexを使用する理由
Vueを使用すると、必然的にコンポーネント間で共有されるデータまたは状態に遭遇します。アプリケーションのビジネスコードはますます複雑になり、小道具、イベント、イベントバスなどの通信方法の欠点がより明らかになります。現時点では、Vuexが必要です。Vuexは、Vue用に特別に設計された状態管理ツールです。
状態管理は、Vueコンポーネントを分離するための重要な手段です。
Fluxとreduxの基本的な考え方を取り入れ、状態を全世界に抽出し、店舗を形成します。
Vuexはコード構造を制限しませんが、いくつかのルールに従う必要があります。
-
アプリケーションレベルの状態は、単一のストアオブジェクトに集中する必要があります
-
状態を変更する唯一の方法は突然変異の送信であり、このプロセスは同期的です
- 非同期ロジックは実際にカプセル化する必要があります
VuexをVueライフサイクルに注入するプロセス
プラグインをインストールするときは、常にVue.use()を使用して次のようにプラグインをロードしますが、Vue.use()は何をしますか?
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
Vue.use()は何をしますか
Vue.jsプラグインをインストールします。プラグインがオブジェクトの場合は、インストール方法を指定する必要があります。プラグインが関数の場合、インストール方法として使用されます。installメソッドが呼び出されると、Vueがパラメーターとして渡されます。
以上が公式文書の説明です。
次に、Vue.use()がソースコード部分から何をするかを見てみましょう。
Vueソースコードは、initGlobalAPIエントリメソッドのinitUse(Vue)メソッドを呼び出します。このメソッドは、Vue.use()が実行する必要があることを定義します。
function initGlobalAPI (Vue) {
......
initUse(Vue);
initMixin$1(Vue); // 下面讲 Vue.mixin 会提到
......
}
function initUse (Vue) {
Vue.use = function (plugin) {
var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
/* 判断过这个插件是否已经安装 */
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
var args = toArray(arguments, 1);
args.unshift(this);
/* 判断插件是否有 install 方法 */
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args);
} else if (typeof plugin === 'function') {
plugin.apply(null, args);
}
installedPlugins.push(plugin);
return this
};
}
このコードは主に2つのことを行います。
-
1つは、同じプラグインの繰り返しインストールを防ぐことです
- もう1つは、プラグインを初期化することです
プラグインのインストール方法
上記のソースコードを読んだ後、プラグイン(Vuex)がインストール方法を提供する必要があることがわかりました。それでは、Vuexソースコードにこのメソッドがあるかどうかを見てみましょう。結果はもちろんです:
/* 暴露给外部的 install 方法 */
function install (_Vue) {
/* 避免重复安装(Vue.use 内部也会检测一次是否重复安装同一个插件)*/
if (Vue && _Vue === Vue) {
{
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
);
}
return
}
Vue = _Vue;
/* 将 vuexInit 混淆进 Vue 的 beforeCreate(Vue2.0) 或 _init 方法(Vue1.0) */
applyMixin(Vue);
}
このコードは主に2つのことを行います。
-
1つは、Vuexが繰り返しインストールされないようにすることです。
- もう1つは、applyMixinを実行することです。目的は、vuexInitメソッドを実行してVuexを初期化することです。
次に、applyMixin(Vue)のソースコードを見てみましょう。
/* 将 vuexInit 混淆进 Vue 的 beforeCreate */
function applyMixin (Vue) {
var version = Number(Vue.version.split('.')[0]);
if (version >= 2) {
Vue.mixin({ beforeCreate: vuexInit });
} else {
/* Vue1.0 的处理逻辑,此处省略 */
......
}
function vuexInit () {
......
}
}
上記のソースコードから、Vue.mixinメソッドがvuexInitメソッドをbeforeCreateフックに混同していることがわかります。この操作のため、各vmインスタンスはvuexInitメソッドを呼び出します。では、vuexInitは何をするのでしょうか?
vuexInit()
Vuexを使用する場合、ストアをVueインスタンスに渡す必要があります。
new Vue({
el: '#app',
store
});
ただし、すべてのvmでストアにアクセスできます。これには、vuexInitが必要です。
function vuexInit () {
const options = this.$options
if (options.store) {
/* 根节点存在 stroe 时 */
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
/* 子组件直接从父组件中获取 $store,这样就保证了所有组件都公用了全局的同一份 store*/
this.$store = options.parent.$store
}
}
ルートノードがストローに存在する場合は、options.storeをthis。$ storeに直接割り当てます。それ以外の場合は、ルートノードではなく、親ノードの$ storeから取得されることを意味します。
この手順により、任意のvmのthis。$ storeを介してStoreインスタンスにアクセスできます。次に、Vue.mixin()について逆に話しましょう。
Vue.mixin()
ミックスインをグローバルに登録し、登録後に作成されるすべてのVueインスタンスに影響を与えます。プラグインの作成者は、ミックスインを使用してカスタム動作をコンポーネントに挿入できます。アプリケーションコードでの使用はお勧めしません。
initMixin $ 1(Vue)メソッドは、vueのinitGlobalAPIエントリメソッドで呼び出されます。
function initMixin$1 (Vue) {
Vue.mixin = function (mixin) {
this.options = mergeOptions(this.options, mixin);
return this
};
}
VuexがVueライフサイクルを注入するプロセスはおそらくこのようなものです。興味がある場合は、Vuexのソースコードを直接見てから、Storeについて話しましょう。
お店
vuexInitはオプションからStoreを取得することを前述しました。では、ストアはどのようにして生まれたのでしょうか。
Vuexを使用する場合、次のようなStoreインスタンスを定義します。
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
Vue.use(Vuex)
const state = {
showState: 0,
}
export default new Vuex.Store({
strict: true,
state,
getters,
})
公開環境で厳密モードを有効にしないでください。厳密モードでは、状態ツリーを詳細に監視して、準拠していない状態の変化を検出します。パフォーマンスの低下を防ぐために、リリース環境では必ず厳密モードをオフにしてください。
応答状態
応答状態がどれほど反応するか気になりますか?これは主に、Storeコンストラクターで呼び出されるresetStoreVM(this、state)メソッドを介して実現されます。
このメソッドは、主にプライベート_vm(Vueのインスタンス)オブジェクトをリセットするためのものです。この_vmオブジェクトは、状態ツリーを保持し、属性を計算することによってストアのゲッターを格納します。それでは、その実装プロセスを詳しく見ていきましょう。
/* 使用 Vue 内部的响应式注册 state */
function resetStoreVM (store, state, hot) {
/* 存放之前的vm对象 */
const oldVm = store._vm
store.getters = {}
const wrappedGetters = store._wrappedGetters
const computed = {}
/* 通过 Object.defineProperty 方法为 store.getters 定义了 get 方法。当在组件中调用 this.$store.getters.xxx 这个方法的时候,会访问 store._vm[xxx]*/
forEachValue(wrappedGetters, (fn, key) => {
computed[key] = partial(fn, store)
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})
const silent = Vue.config.silent
/* 设置 silent 为 true 的目的是为了取消 _vm 的所有日志和警告 */
Vue.config.silent = true
/* 这里new了一个Vue对象,运用Vue内部的响应式实现注册state以及computed*/
store._vm = new Vue({
data: {
$$state: state
},
computed
})
Vue.config.silent = silent
/* 使能严格模式,Vuex 中对 state 的修改只能在 mutation 的回调函数里 */
if (store.strict) {
enableStrictMode(store)
}
if (oldVm) {
/* 解除旧 vm 的 state 的引用,并销毁这个旧的 _vm 对象 */
if (hot) {
store._withCommit(() => {
oldVm._data.$$state = null
})
}
Vue.nextTick(() => oldVm.$destroy())
}
}
応答状態の状態は、おそらくこの方法で実装されます。これは、resetStoreVMメソッドを初期化するプロセスです。
Storeのcommitメソッドを見てください
commitメソッドを使用してミューテーションをトリガーすることはわかっています。
commit (_type, _payload, _options) {
/* unifyObjectStyle 方法校参 */
const {
type,
payload,
options
} = unifyObjectStyle(_type, _payload, _options)
const mutation = { type, payload }
/* 找到相应的 mutation 方法 */
const entry = this._mutations[type]
if (!entry) {
if (process.env.NODE_ENV !== 'production') {
console.error(`[vuex] unknown mutation type: ${type}`)
}
return
}
/* 执行 mutation 中的方法 */
this._withCommit(() => {
entry.forEach(function commitIterator (handler) {
handler(payload)
})
})
/* 通知所有订阅者,传入当前的 mutation 对象和当前的 state */
this._subscribers.forEach(sub => sub(mutation, this.state))
if (
process.env.NODE_ENV !== 'production' &&
options && options.silent
) {
console.warn(
`[vuex] mutation type: ${type}. Silent option has been removed. ` +
'Use the filter functionality in the vue-devtools'
)
}
}
このメソッドは、最初にパラメータースタイルの検証を実行し、次に_withCommitメソッドを使用してこのバッチトリガーミューテーション処理関数を実行します。実行が完了したら、この操作のミューテーションオブジェクトと現在の状態をすべての_subscribers(サブスクリプション関数)に通知します。
Vue関連記事の出力計画
最近、友達からいつもVue関連の質問が寄せられているので、皆さんのお役に立てればと思って、次はVue関連の記事を9つ出力します。更新は7〜10日で行います。
-
[フロントエンド辞書] VuexがVueライフサイクルを注入するプロセス
-
[フロントエンド辞書] Vue応答原理の分析
-
[フロントエンド辞書]新旧のVNodeにパッチを適用するプロセス
-
[フロントエンド辞書]機能コンポーネントの開発方法とnpmのアップロード方法
-
[フロントエンド辞書]これらの側面からVueプロジェクトを最適化する
-
[フロントエンド辞書] Vue-Router設計からのフロントエンドルーティングの開発について話します
-
【フロントエンド辞書】プロジェクトでWebpackを正しく使う方法
-
【フロントエンド辞書】Vueサーバーレンダリング
- 【フロントエンド辞書】AxiosとFetchの選び方
私の公式アカウントに注意を払うことをお勧めします。できるだけ早く最新の記事を受け取ることができます。
グループコミュニケーションに参加したい場合は、私のWeChatwqhhsdを追加することもできます。