欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

solid.js響應(yīng)式createSignal 源碼解析

 更新時(shí)間:2022年09月14日 16:34:31   作者:heora  
這篇文章主要為大家介紹了solid.js響應(yīng)式createSignal 源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

www.solidjs.com/docs/latest…

createSignal 用來創(chuàng)建響應(yīng)式數(shù)據(jù),它可以跟蹤單個(gè)值的變化。

solid.js 的響應(yīng)式實(shí)現(xiàn)參考了 S.js,它是一個(gè)體積超小的 reactive 庫,支持自動(dòng)收集依賴和簡單的響應(yīng)式編程。

createSignal

createSignal

首先我們來看下 createSignal 的聲明:

// packages/solid/src/reactive/signal.ts
export interface BaseOptions {
  name?: string;
}
export interface EffectOptions extends BaseOptions {}
export interface MemoOptions<T> extends EffectOptions {
  equals?: false | ((prev: T, next: T) => boolean);
}
export type Accessor<T> = () => T;
export type Setter<T> = (undefined extends T ? () => undefined : {}) &
  (<U extends T>(value: (prev: T) => U) => U) &
  (<U extends T>(value: Exclude<U, Function>) => U) &
  (<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)) => U);
// packages/solid/src/reactive/signal.ts
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
export interface SignalOptions<T> extends MemoOptions<T> {
  internal?: boolean;
}
export function createSignal<T>(): Signal<T | undefined>;
export function createSignal<T>(value: T, options?: SignalOptions<T>): Signal<T>;

可以看到 createSignal 支持兩個(gè)參數(shù),分別是 value 和 options,然后返回一個(gè)包含 setter 和 getter 的數(shù)組。

參數(shù):

  • value:初始值,默認(rèn)值為 undefiend
  • options
    • equals:自定義比較器,用于新舊值比較或觸發(fā)強(qiáng)制更新,允許傳遞函數(shù)或者 false;
    • internal(可選):標(biāo)識(shí)是否為內(nèi)置屬性,應(yīng)用于開發(fā)環(huán)境,生產(chǎn)環(huán)境會(huì)移除掉相關(guān)邏輯;
    • name(可選):自定義屬性對象名稱,應(yīng)用于開發(fā)環(huán)境,生產(chǎn)環(huán)境會(huì)移除掉相關(guān)邏輯。

返回值:

  • getter:返回當(dāng)前值,以函數(shù)形式調(diào)用
    • 自動(dòng)進(jìn)行依賴收集。例如在 createEffect 中調(diào)用 getter, state 對象會(huì)與 effect 建立依賴關(guān)系。
  • setter:設(shè)置值,以函數(shù)形式調(diào)用
    • 如果存在依賴當(dāng)前 state 對象的觀察者,循環(huán)執(zhí)行觀察者數(shù)組。

了解 createSignal 聲明之后,下面我們來看下具體實(shí)現(xiàn)。

// packages/solid/src/reactive/signal.ts
export function createSignal<T>(value?: T, options?: SignalOptions<T>): Signal<T | undefined> {
  options = options ? Object.assign({}, signalOptions, options) : signalOptions;
  const s: SignalState<T> = {
    value,
    observers: null,
    observerSlots: null,
    comparator: options.equals || undefined
  };
  if ("_SOLID_DEV_" && !options.internal)
    s.name = registerGraph(options.name || hashValue(value), s as { value: unknown });
  const setter: Setter<T | undefined> = (value?: unknown) => {
    if (typeof value === "function") {
      if (Transition && Transition.running && Transition.sources.has(s)) value = value(s.tValue);
      else value = value(s.value);
    }
    return writeSignal(s, value);
  };
  return [readSignal.bind(s), setter];
}

如果用戶傳入 options,會(huì)對 options 和默認(rèn)的 options 進(jìn)行合并,否則使用默認(rèn) options。

// packages/solid/src/reactive/signal.ts
export const equalFn = <T>(a: T, b: T) => a === b;
const signalOptions = { equals: equalFn };

默認(rèn)配置只有一個(gè) equals 屬性,值為 equalFn ,用于比較兩個(gè)值是否相同。

由于這里比較的是引用地址,所以當(dāng)你改變一個(gè)對象的某個(gè)屬性,重新賦值時(shí),相關(guān)訂閱并不會(huì)被觸發(fā),所以這時(shí)我們可以在傳入的 options 配置中配置 equals 為 false 或者自定義其他比較邏輯。

例如下面的案例:

const [object, setObject] = createSignal({ count: 0 });
createEffect(() => {
  console.log(object());
});
object().count = 2;
setObject(object);
setObject(current => {
  current.count += 1;
  current.updated = new Date();
  return current;
});
// { count: 0 }

上述代碼在運(yùn)行時(shí) effect 中代碼只會(huì)觸發(fā)一次,這可能與我們的預(yù)期不符,所以我們可以傳入自定義 options。

const [object, setObject] = createSignal({ count: 0 }, { equals: false });
// { count: 0 }
// { count: 2 }
// { count: 3, updated: 2022-09-11T08:21:44.258Z }

當(dāng)我們設(shè)置 equals 屬性為 false,effect 就會(huì)被觸發(fā) 3 次。

除此之外,我們還可以使用該配置作為觸發(fā)器來使用,這里就不展開闡述了。感興趣可以查看官方提供的案例,createSignal。

下面讓我們繼續(xù)查看代碼:

// packages/solid/src/reactive/signal.ts
export interface SignalState<T> {
  value?: T;
  observers: Computation<any>[] | null;
  observerSlots: number[] | null;
  tValue?: T;
  comparator?: (prev: T, next: T) => boolean;
  name?: string;
}
export function createSignal<T>(value?: T, options?: SignalOptions<T>): Signal<T | undefined> {
  options = options ? Object.assign({}, signalOptions, options) : signalOptions;
  const s: SignalState<T> = {
    value,
    observers: null,
    observerSlots: null,
    comparator: options.equals || undefined
  };
  if ("_SOLID_DEV_" && !options.internal)
    s.name = registerGraph(options.name || hashValue(value), s as { value: unknown });
  const setter: Setter<T | undefined> = (value?: unknown) => {
    if (typeof value === "function") {
      if (Transition && Transition.running && Transition.sources.has(s)) value = value(s.tValue);
      else value = value(s.value);
    }
    return writeSignal(s, value);
  };
  return [readSignal.bind(s), setter];
}

createSignal 定義了 s 對象,它有四個(gè)屬性,分別是:

  • value:傳入的值
  • observers:觀察者數(shù)組
  • observerSlots:觀察者對象在數(shù)組的位置
  • comparator:比較器
// packages/solid/src/reactive/signal.ts
if ("_SOLID_DEV_" && !options.internal)
  s.name = registerGraph(options.name || hashValue(value), s as { value: unknown });

這段代碼為 state 對象設(shè)置了 name 屬性,不過它只作用于開發(fā)環(huán)境,生產(chǎn)環(huán)境打包時(shí) _SOLID_DEV_ 變量會(huì)被替換為 false,然后會(huì)作為 decode 被移除掉。

// packages/solid/rollup.config.js
export default [
  {
    input: "src/index.ts",
		// ...
    plugins: [
      replace({
        '"_SOLID_DEV_"': false,
        preventAssignment: true,
        delimiters: ["", ""]
      })
    ].concat(plugins)
  }
]

接下來定義 setter 函數(shù):首先會(huì)對 value 的值進(jìn)行判斷,如果傳遞的 setter 是一個(gè) 函數(shù):

  • 如果發(fā)現(xiàn) Transition 存在,并且 Transition.sources 中存在當(dāng)前 state,會(huì)使用 s.tValue 屬性值;
  • 如果上述條件不滿足,會(huì)使用當(dāng)前 state 的 value 屬性值。

然后調(diào)用 wrtieSignal,并返回其結(jié)果。

// packages/solid/src/reactive/signal.ts
export function createSignal<T>(value?: T, options?: SignalOptions<T>): Signal<T | undefined> {
 	// ...
  const setter: Setter<T | undefined> = (value?: unknown) => {
    if (typeof value === "function") {
      if (Transition && Transition.running && Transition.sources.has(s)) value = value(s.tValue);
      else value = value(s.value);
    }
    return writeSignal(s, value);
  };
  return [readSignal.bind(s), setter];
}

最后返回操作數(shù)組:第一個(gè)參數(shù)為 readSignal 函數(shù),用來返回 s 中的 value 值,第二個(gè)參數(shù)就是 setter。

總結(jié)一下,createSignal 首先會(huì)合并用戶 options,其次會(huì)定義 state 對象,用來記錄當(dāng)前值和依賴關(guān)系,然后定義 setter 函數(shù),用來設(shè)置值,最后返回一個(gè)數(shù)組,分別是 readSignal 函數(shù)和 setter 函數(shù)。

readSignal

readSignal

看完 createSignal 定義,接著我們再來看下 readSignal,這個(gè)方法非常重要。solid.js 依賴關(guān)系的建立就發(fā)生在這個(gè)方法中。

// packages/solid/src/reactive/signal.ts
// Internal
export function readSignal(this: SignalState<any> | Memo<any>) {
  const runningTransition = Transition && Transition.running;
  if (
    (this as Memo<any>).sources &&
    ((!runningTransition && (this as Memo<any>).state) ||
      (runningTransition && (this as Memo<any>).tState))
  ) {
    if (
      (!runningTransition && (this as Memo<any>).state === STALE) ||
      (runningTransition && (this as Memo<any>).tState === STALE)
    )
      updateComputation(this as Memo<any>);
    else {
      const updates = Updates;
      Updates = null;
      runUpdates(() => lookUpstream(this as Memo<any>), false);
      Updates = updates;
    }
  }
  if (Listener) {
    const sSlot = this.observers ? this.observers.length : 0;
    if (!Listener.sources) {
      Listener.sources = [this];
      Listener.sourceSlots = [sSlot];
    } else {
      Listener.sources.push(this);
      Listener.sourceSlots!.push(sSlot);
    }
    if (!this.observers) {
      this.observers = [Listener];
      this.observerSlots = [Listener.sources.length - 1];
    } else {
      this.observers.push(Listener);
      this.observerSlots!.push(Listener.sources.length - 1);
    }
  }
  if (runningTransition && Transition!.sources.has(this)) return this.tValue;
  return this.value;
}

函數(shù)內(nèi)部首先判斷是否正在 transition,我們暫時(shí)不需要關(guān)心這段邏輯,直接跳到下面這段邏輯:

// packages/solid/src/reactive/signal.ts
export function readSignal(this: SignalState<any> | Memo<any>) {
	// ...
  if (Listener) {
    const sSlot = this.observers ? this.observers.length : 0;
    if (!Listener.sources) {
      Listener.sources = [this];
      Listener.sourceSlots = [sSlot];
    } else {
      Listener.sources.push(this);
      Listener.sourceSlots!.push(sSlot);
    }
    if (!this.observers) {
      this.observers = [Listener];
      this.observerSlots = [Listener.sources.length - 1];
    } else {
      this.observers.push(Listener);
      this.observerSlots!.push(Listener.sources.length - 1);
    }
  }
  if (runningTransition && Transition!.sources.has(this)) return this.tValue;
  return this.value;
}

首先會(huì)判斷 Listener 是否存在,如果存在才會(huì)執(zhí)行這段代碼。那么這個(gè) Listener 是什么時(shí)候被定義并賦值的呢?

// packages/solid/src/reactive/signal.ts
let Listener: Computation<any> | null = null;
let Updates: Computation<any>[] | null = null;
let Effects: Computation<any>[] | null = null;

Listener 是一個(gè)全局變量,默認(rèn)值是 null。同時(shí)還定義了 Updates、Effectes 數(shù)組,它們都是 Computation 類型。

export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
export interface SignalState<T> {
  value?: T;
  observers: Computation<any>[] | null;
  observerSlots: number[] | null;
  tValue?: T;
  comparator?: (prev: T, next: T) => boolean;
  name?: string;
}
export interface Owner {
  owned: Computation<any>[] | null;
  cleanups: (() => void)[] | null;
  owner: Owner | null;
  context: any | null;
  sourceMap?: Record<string, { value: unknown }>;
  name?: string;
  componentName?: string;
}
export interface Computation<Init, Next extends Init = Init> extends Owner {
  fn: EffectFunction<Init, Next>;
  state: number;
  tState?: number;
  sources: SignalState<Next>[] | null;
  sourceSlots: number[] | null;
  value?: Init;
  updatedAt: number | null;
  pure: boolean;
  user?: boolean;
  suspense?: SuspenseContextType;
}

可以看到 Computation 是一個(gè)對象,定義了很多屬性,基本都不知道啥作用。不過其中一個(gè) sources 屬性,你是否也感覺很眼熟?

對,它就是一個(gè)普通的 signal 對象,也就是我們調(diào)用 createSignal 方法時(shí),內(nèi)部創(chuàng)建的 s 對象。

另外可以看到,上面 SignalState 接口聲明中的 observers 就是一個(gè) Computation 類型的數(shù)組,這時(shí)我們已經(jīng)知道 state 和 computation 互相依賴,并且是多對多的關(guān)系。

接下來再回到代碼:

// packages/solid/src/reactive/signal.ts
export function readSignal(this: SignalState<any> | Memo<any>) {
	// ...
  if (Listener) {
    const sSlot = this.observers ? this.observers.length : 0;
    if (!Listener.sources) {
      Listener.sources = [this];
      Listener.sourceSlots = [sSlot];
    } else {
      Listener.sources.push(this);
      Listener.sourceSlots!.push(sSlot);
    }
    if (!this.observers) {
      this.observers = [Listener];
      this.observerSlots = [Listener.sources.length - 1];
    } else {
      this.observers.push(Listener);
      this.observerSlots!.push(Listener.sources.length - 1);
    }
  }
  if (runningTransition && Transition!.sources.has(this)) return this.tValue;
  return this.value;
}

當(dāng) Listener 存在時(shí),首先會(huì)獲取當(dāng)前 observers 的數(shù)量,如果不存在就是 0,這里的 this 就是 s 對象。

export function createSignal<T>(value?: T, options?: SignalOptions<T>): Signal<T | undefined> {
	// ...
  return [readSignal.bind(s), setter];
}

接下來分別判斷 Listener.sources 和 this.observers 是否存在,如果不存在會(huì)創(chuàng)建數(shù)組,并建立依賴關(guān)系。最后將 s 對象的 value 返回。這里的 value 就是我們調(diào)用 createSignal 傳入的初始值。

不同于 vue 中 通過 Proxy 或者 Object.defineProperty 進(jìn)行屬性劫持,solid.js 中的依賴關(guān)系建立是通過函數(shù)調(diào)用實(shí)現(xiàn)的,例如在 createEffect 中調(diào)用 getter 函數(shù),這時(shí)就會(huì)建立依賴關(guān)系。

writeSignal

writeSignal

我們已經(jīng)知道,通過 getter 可以建立 compulation 和 state 之間的依賴關(guān)系。setter 函數(shù)其實(shí)就是用來觸發(fā)依賴。

export function writeSignal(node: SignalState<any> | Memo<any>, value: any, isComp?: boolean) {
  let current =
    Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value;
  if (!node.comparator || !node.comparator(current, value)) {
    if (Transition) {
      const TransitionRunning = Transition.running;
      if (TransitionRunning || (!isComp && Transition.sources.has(node))) {
        Transition.sources.add(node);
        node.tValue = value;
      }
      if (!TransitionRunning) node.value = value;
    } else node.value = value;
    if (node.observers && node.observers.length) {
      runUpdates(() => {
        for (let i = 0; i < node.observers!.length; i += 1) {
          const o = node.observers![i];
          const TransitionRunning = Transition && Transition.running;
          if (TransitionRunning && Transition!.disposed.has(o)) continue;
          if ((TransitionRunning && !o.tState) || (!TransitionRunning && !o.state)) {
            if (o.pure) Updates!.push(o);
            else Effects!.push(o);
            if ((o as Memo<any>).observers) markDownstream(o as Memo<any>);
          }
          if (TransitionRunning) o.tState = STALE;
          else o.state = STALE;
        }
        if (Updates!.length > 10e5) {
          Updates = [];
          if ("_SOLID_DEV_") throw new Error("Potential Infinite Loop Detected.");
          throw new Error();
        }
      }, false);
    }
  }
  return value;
}

writeSignal 接收兩個(gè)參數(shù),第一個(gè)參數(shù)就是 state 對象,第二個(gè)參數(shù)就是我們傳入的值。

首先獲取 current,我們暫時(shí)忽略 Transition 相關(guān)的判斷邏輯,這里的 current 就是 state 的值,也就是舊值。

當(dāng) node.comparator 為 false,或者新值和舊值不同時(shí),才會(huì)進(jìn)行賦值和觸發(fā)更新。

comparator 可以被賦值為 false 或者一個(gè)函數(shù),默認(rèn) comparator 只會(huì)比較新值和舊值引用是否相同,這里我們后面再去分析。

當(dāng)傳入的值與舊值不同,將新值賦值 node.value。然后判斷 node 是否存在觀察者,如果存在會(huì)循環(huán)遍歷 observers 數(shù)組,根據(jù)不同邏輯放入 Updates 或者 Effects 數(shù)組,不過最終都會(huì)執(zhí)行 observer 對象,即 computation 對象。

案例分析

我們可以通過源碼調(diào)試的方式對代碼進(jìn)行分析。

我們來看下面這個(gè)例子。

const { createSignal } = require("../../solid/dist/solid.cjs");
const [count, setCount] = createSignal(0);
console.log(count());
setCount(count() + 1);
console.log(count());

例子很簡單,就是創(chuàng)建一個(gè)響應(yīng)式數(shù)據(jù),打印它,改變值后繼續(xù)對其進(jìn)行打印。

當(dāng) createSignal 函數(shù)被執(zhí)行完畢之前,我們可以可以看到 s 對象已經(jīng)被創(chuàng)建,value 值為 0,observers 為 null。

接下來執(zhí)行第一次打印,這時(shí)會(huì)觸發(fā) readSignal 函數(shù)。

可以看到,this 其實(shí)就是 state 對象,此時(shí) runningTransition 和 Listerner 都為空,什么都不會(huì)執(zhí)行,直接返回 s.value。

當(dāng)執(zhí)行到 setCount(count() + 1) 這段代碼時(shí),首先會(huì)取到 state 的 value 值,然后再進(jìn)行計(jì)算,并將結(jié)果傳給 setter 函數(shù),觸發(fā) writeSignal 函數(shù)。

可以看到,current 的值是 0,此時(shí) comparator 肯定是存在的,并且兩個(gè)值并不相等,由于 Transition 不存在,所以會(huì)將 value 賦值給 node.value,此時(shí) state 的 value 值已經(jīng)變?yōu)?1。由于 node.observers` 也不存在,所以會(huì)直接返回傳入的 value ,函數(shù)執(zhí)行完畢。

接下來執(zhí)行最后一次打印,和之前的過程一樣,這里只是做了一次取值操作,打印出改變后的結(jié)果 1。

我們還可以調(diào)試其他案例,比如給 createSignal 傳遞第二個(gè)參數(shù),配置 name 和 equals 屬性然后查看代碼的變化。

相關(guān)案例

總結(jié)

createSignal 用于創(chuàng)建響應(yīng)式數(shù)據(jù),其內(nèi)部定義了一個(gè) s 對象,保存當(dāng)前值和依賴關(guān)系,并返回 getter 函數(shù)和 setter 函數(shù)。

當(dāng)調(diào)用 getter 函數(shù)讀取值時(shí),如果存在 Listener,雙方會(huì)建立依賴關(guān)系,即將 Listener 添加到 state 的 observers 數(shù)組中,將 state 添加到 Listener 的 sources 數(shù)組中, 并返回當(dāng)前值。

當(dāng)調(diào)用 settter 函數(shù)賦值時(shí),如果存在 observers,會(huì)遍歷 observers 數(shù)組,并根據(jù)邏輯加入 Updates 或 Effects 數(shù)組中,最后去執(zhí)行它們,觸發(fā)副作用函數(shù)執(zhí)行。

以上就是solid.js響應(yīng)式createSignal 源碼解析的詳細(xì)內(nèi)容,更多關(guān)于solid.js createSignal源碼的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 在vue中通過render函數(shù)給子組件設(shè)置ref操作

    在vue中通過render函數(shù)給子組件設(shè)置ref操作

    這篇文章主要介紹了在vue中通過render函數(shù)給子組件設(shè)置ref操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Vue項(xiàng)目導(dǎo)入字體文件的方法步驟

    Vue項(xiàng)目導(dǎo)入字體文件的方法步驟

    有些時(shí)候客戶希望產(chǎn)品使用他們公司要求的字體,這個(gè)時(shí)候我們需要將客戶提供的字體文件引入到項(xiàng)目中,下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目導(dǎo)入字體文件的方法步驟,需要的朋友可以參考下
    2024-03-03
  • vue 不使用select實(shí)現(xiàn)下拉框功能(推薦)

    vue 不使用select實(shí)現(xiàn)下拉框功能(推薦)

    這篇文章主要介紹了vue 不使用select實(shí)現(xiàn)下拉框功能,在文章給大家提到了vue select 組件的使用與禁用,需要的朋友可以參考下
    2018-05-05
  • vue+ElementUi+iframe實(shí)現(xiàn)輪播不同的網(wǎng)站

    vue+ElementUi+iframe實(shí)現(xiàn)輪播不同的網(wǎng)站

    需要實(shí)現(xiàn)一個(gè)輪播圖,輪播內(nèi)容是不同的網(wǎng)站,并實(shí)現(xiàn)鼠標(biāo)滑動(dòng)時(shí)停止輪播,當(dāng)鼠標(biāo)10秒內(nèi)不動(dòng)時(shí)繼續(xù)輪播,所以本文給大家介紹了用vue+ElementUi+iframe實(shí)現(xiàn)輪播不同的網(wǎng)站,需要的朋友可以參考下
    2024-02-02
  • vue+element ui el-tooltip動(dòng)態(tài)顯示隱藏問題

    vue+element ui el-tooltip動(dòng)態(tài)顯示隱藏問題

    這篇文章主要介紹了vue+element ui el-tooltip動(dòng)態(tài)顯示隱藏問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue3使用postcss-px-to-viewport實(shí)現(xiàn)頁面自適應(yīng)

    Vue3使用postcss-px-to-viewport實(shí)現(xiàn)頁面自適應(yīng)

    postcss-px-to-viewport 是一個(gè) PostCSS 插件,它可以將 px 單位轉(zhuǎn)換為視口單位,下面我們就看看如何使用postcss-px-to-viewport實(shí)現(xiàn)頁面自適應(yīng)吧
    2024-01-01
  • 解決vue項(xiàng)目Error:Cannot find module‘xxx’類報(bào)錯(cuò)問題

    解決vue項(xiàng)目Error:Cannot find module‘xxx’類報(bào)錯(cuò)問題

    當(dāng)npm運(yùn)行報(bào)錯(cuò)Error:Cannot find module 'xxx'時(shí),通常是因?yàn)閚ode_modules文件或依賴未正確安裝,解決步驟包括刪除node_modules和package-lock.json文件,重新運(yùn)行npm install,并根據(jù)需要安裝額外插件,若網(wǎng)絡(luò)問題導(dǎo)致安裝失敗
    2024-10-10
  • Vue.js 中的 $watch使用方法

    Vue.js 中的 $watch使用方法

    本篇文章中主要介紹了Vue.js 中的 $watch使用方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • 解決vue項(xiàng)目獲取dom元素寬高總是不準(zhǔn)確問題

    解決vue項(xiàng)目獲取dom元素寬高總是不準(zhǔn)確問題

    這篇文章主要介紹了解決vue項(xiàng)目獲取dom元素寬高總是不準(zhǔn)確問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • vuex中store的action和mutations用法

    vuex中store的action和mutations用法

    這篇文章主要介紹了vuex中store的action和mutations用法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04

最新評論