亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

利用Dectorator分模塊存儲Vuex狀態的實現

2019-11-19 12:10:26
字體:
來源:轉載
供稿:網友

1、引言

在H5的Vue項目中,最為常見的當為單頁應用(SPA),利用Vue-Router控制組件的掛載與復用,這時使用Vuex可以方便的維護數據狀態而不必關心組件間的數據通信。但在Weex中,不同的頁面之間使用不同的執行環境,無法共享數據,此時多為通過BroadcastChannel或storage模塊來實現數據通信,本文主要使用修飾器(Decorator)來擴展Vuex的功能,實現分模塊存儲數據,并降低與業務代碼的耦合度。

2、Decorator

設計模式中有一種裝飾器模式,可以在運行時擴展對象的功能,而無需創建多個繼承對象。類似的,Decorator可以在編譯時擴展一個對象的功能,降低代碼耦合度的同時實現多繼承一樣的效果。

2.1、Decorator安裝

目前Decorator還只是一個提案,在生產環境中無法直接使用,可以用babel-plugin-transform-decorators-legacy來實現。使用npm管理依賴包的可以執行以下命令:

npm install babel-plugin-transform-decorators-legacy -D

然后在 .babelrc 中配置

{  "plugins": [    "transform-decorators-legacy"  ]}

或者在webpack.config.js中配置

{  test: //.js$/,  loader: "babel-loader",  options: [    plugins: [      require("babel-plugin-transform-decorators-legacy").default    ]  ]}

這時可以在代碼里編寫Decorator函數了。

2.2、Decorator的編寫

在本文中,Decorator主要是對方法進行修飾,主要代碼如下:
decorator.js

const actionDecorator = (target, name, descriptor) => {  const fn = descriptor.value;  descriptor.value = function(...args) {    console.log('調用了修飾器的方法');    return fn.apply(this, args);  };  return descriptor;};

store.js

const module = {  state: () => ({}),  actions: {    @actionDecorator    someAction() {/** 業務代碼 **/ },  },};

可以看到,actionDecorator修飾器的三個入參和Object.defineProperty一樣,通過對module.actions.someAction函數的修飾,實現在編譯時重寫someAction方法,在調用方法時,會先執行console.log('調用了修飾器的方法');,而后再調用方法里的業務代碼。對于多個功能的實現,比如存儲數據,發送廣播,打印日志和數據埋點,增加多個Decorator即可。

3、Vuex

Vuex本身可以用subscribe和subscribeAction訂閱相應的mutation和action,但只支持同步執行,而Weex的storage存儲是異步操作,因此需要對Vuex的現有方法進行擴展,以滿足相應的需求。

3.1、修飾action

在Vuex里,可以通過commit mutation或者dispatch action來更改state,而action本質是調用commit mutation。因為storage包含異步操作,在不破壞Vuex代碼規范的前提下,我們選擇修飾action來擴展功能。

storage使用回調函數來讀寫item,首先我們將其封裝成Promise結構:

storage.js

const storage = weex.requireModule('storage');const handler = { get: function(target, prop) {  const fn = target[prop];  // 這里只需要用到這兩個方法  if ([   'getItem',   'setItem'  ].some(method => method === prop)) {   return function(...args) {    // 去掉回調函數,返回promise    const [callback] = args.slice(-1);    const innerArgs = typeof callback === 'function' ? args.slice(0, -1) : args;    return new Promise((resolve, reject) => {     fn.call(target, ...innerArgs, ({result, data}) => {      if (result === 'success') {       return resolve(data);      }      // 防止module無保存state而出現報錯      return resolve(result);     })    })   }  }  return fn; },};export default new Proxy(storage, handler);

通過Proxy,將setItem和getItem封裝為promise對象,后續使用時可以避免過多的回調結構。

現在我們把storage的setItem方法寫入到修飾器:

decorator.js

import storage from './storage';// 加個rootKey,防止rootState的namespace為''而導致報錯// 可自行替換為其他字符串import {rootKey} from './constant';const setState = (target, name, descriptor) => {  const fn = descriptor.value;  descriptor.value = function(...args) {    const [{state, commit}] = args;    // action為異步操作,返回promise,    // 且需在狀態修改為fulfilled時再將state存儲到storage    return fn.apply(this, args).then(async data => {      // 獲取store的moduleMap      const rawModule = Object.entries(this._modulesNamespaceMap);      // 根據當前的commit,查找此action所在的module      const moduleMap = rawModule.find(([, module]) => {        return module.context.commit === commit;      });      if (moduleMap) {        const [key, {_children}] = moduleMap;        const childrenKeys = Object.keys(_children);        // 只獲取當前module的state,childModule的state交由其存儲,按module存儲數據,避免存儲數據過大        // Object.fromEntries可使用object.fromentries來polyfill,或可用reduce替代        const pureState = Object.fromEntries(Object.entries(state).filter(([stateKey]) => {          return !childrenKeys.some(childKey => childKey === stateKey);        }));        await storage.setItem(rootKey + key, JSON.stringify(pureState));      }      // 將data沿著promise鏈向后傳遞      return data;    });  };  return descriptor;};export default setState;

完成了setState修飾器功能以后,就可以裝飾action方法了,這樣等action返回的promise狀態修改為fulfilled后調用storage的存儲功能,及時保存數據狀態以便在新開Weex頁面加載最新數據。

store.js

import setState from './decorator';const module = {  state: () => ({}),  actions: {    @setState    someAction() {/** 業務代碼 **/ },  },};

3.2、讀取module數據

完成了存儲數據到storage以后,我們還需要在新開的Weex頁面實例能自動讀取數據并初始化Vuex的狀態。在這里,我們使用Vuex的plugins設置來完成這個功能。

首先我們先編寫Vuex的plugin:

plugin.js

import storage from './storage';import {rootKey} from './constant';const parseJSON = (str) => {  try {    return str ? JSON.parse(str) : undefined;  } catch(e) {}  return undefined;};const getState = (store) => {  const getStateData = async function getModuleState(module, path = []) {    const {_children} = module;    // 根據path讀取當前module下存儲在storage里的數據    const data = parseJSON(await storage.getItem(`${path.join('/')}/`)) || {};    const children = Object.entries(_children);    if (!children.length) {      return data;    }    // 剔除childModule的數據,遞歸讀取    const childModules = await Promise.all(      children.map(async ([childKey, child]) => {       return [childKey, await getModuleState(child, path.concat(childKey))];      })    );    return {      ...data,      ...Object.fromEntries(childModules),    }  };  // 讀取本地數據,merge到Vuex的state  const init = getStateData(store._modules.root, [rootKey]).then(savedState => {    store.replaceState(merge(store.state, savedState, {      arrayMerge: function (store, saved) { return saved },      clone: false,    }));  });};export default getState;

以上就完成了Vuex的數據按照module讀取,但Weex的IOS/Andriod中的storage存儲是異步的,為防止組件掛載以后發送請求返回的數據被本地數據覆蓋,需要在本地數據讀取并merge到state以后再調用new Vue,這里我們使用一個簡易的interceptor來攔截:

interceptor.js

const interceptors = {};export const registerInterceptor = (type, fn) => {  const interceptor = interceptors[type] || (interceptors[type] = []);  interceptor.push(fn);};export const runInterceptor = async (type) => {  const task = interceptors[type] || [];  return Promise.all(task);};

這樣plugin.js中的getState就修改為:

import {registerInterceptor} from './interceptor';const getState = (store) => {  /** other code **/  const init = getStateData(store._modules.root, []).then(savedState => {    store.replaceState(merge(store.state, savedState, {      arrayMerge: function (store, saved) { return saved },      clone: false,    }));  });  // 將promise放入攔截器  registerInterceptor('start', init);};

store.js

import getState from './plugin';import setState from './decorator';const rootModule = {  state: {},  actions: {    @setState    someAction() {/** 業務代碼 **/ },  },  plugins: [getState],  modules: {    /** children module**/  }};

app.js

import {runInterceptor} from './interceptor';// 待攔截器內所有promise返回resolved后再實例化Vue根組件// 也可以用Vue-Router的全局守衛來完成runInterceptor('start').then(() => {  new Vue({/** other code **/});});

這樣就實現了Weex頁面實例化后,先讀取storage數據到Vuex的state,再實例化各個Vue的組件,更新各自的module狀態。

4、TODO

通過Decorator實現了Vuex的數據分模塊存儲到storage,并在Store實例化時通過plugin分模塊讀取數據再merge到state,提高數據存儲效率的同時實現與業務邏輯代碼的解耦。但還存在一些可優化的點:

1、觸發action會將所有module中的所有state全部,只需保存所需狀態,避免存儲無用數據。

2、對于通過registerModule注冊的module,需支持自動讀取本地數據。

3、無法通過_modulesNamespaceMap獲取namespaced為false的module,需改為遍歷_children。

在此不再展開,將在后續版本中實現。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩国产成人| 最新亚洲国产精品| 久久精品一本久久99精品| 亚洲国产精品yw在线观看| 91a在线视频| 欧美大片在线免费观看| 国内成人精品一区| 亚洲精品视频免费在线观看| 国产成人精品在线播放| 91av视频在线播放| 日韩免费电影在线观看| 精品国产一区av| 欧美俄罗斯性视频| 欧美激情在线视频二区| 欧美日韩激情美女| 国产精品久久久久久久久久99| 欧美高清理论片| 亚洲欧美综合另类中字| 欧美xxxx18性欧美| 国产一区香蕉久久| 91国内免费在线视频| 在线观看亚洲区| 亚洲aa中文字幕| 国产精品激情av电影在线观看| 久久久久久久国产精品| 久久大大胆人体| 国产精品久久久久久久美男| 国产精品久久久久久久久免费看| 国产精品久久久久久久久久| 欧美一区二区影院| 97免费在线视频| 精品无人国产偷自产在线| 黑人狂躁日本妞一区二区三区| 国产精品一区二区三区成人| 亚洲欧美中文日韩v在线观看| 色综合久久中文字幕综合网小说| 日韩av成人在线观看| 国产精品青青在线观看爽香蕉| 午夜欧美不卡精品aaaaa| 欧美日韩中国免费专区在线看| 欧美成人在线免费| 欧美日韩加勒比精品一区| 国a精品视频大全| 欧美黑人性生活视频| 久久久久久国产三级电影| 国产综合在线看| 亚洲欧洲xxxx| 亚洲精品中文字| 亚洲毛茸茸少妇高潮呻吟| 欧美日韩在线免费| 欧美精品在线播放| 777午夜精品福利在线观看| 久久精品电影网站| 色先锋久久影院av| 国产一区深夜福利| 国产男人精品视频| 欧美成人中文字幕| 97激碰免费视频| 日韩在线一区二区三区免费视频| 中文字幕精品影院| 欧美中文字幕在线观看| 亚洲欧美综合精品久久成人| 欧美视频中文字幕在线| 91在线播放国产| 日韩精品视频在线免费观看| 懂色av一区二区三区| 国产精品精品视频一区二区三区| 国模视频一区二区三区| 久操成人在线视频| 欧美亚洲在线视频| 2019中文字幕在线免费观看| 98午夜经典影视| 国产日韩在线观看av| 国产主播在线一区| www.精品av.com| 欧美激情亚洲视频| 高清在线视频日韩欧美| 综合av色偷偷网| 亚洲色图校园春色| 国产亚洲精品一区二区| 亚洲一区二区自拍| 久久久中文字幕| 国外成人免费在线播放| 日韩电影中文字幕在线观看| 久久中文字幕视频| 成人乱人伦精品视频在线观看| 97在线视频免费看| 国产91精品最新在线播放| 国产精品视频自拍| 美乳少妇欧美精品| 日韩亚洲精品视频| 国产精品狼人色视频一区| 亚洲片在线资源| 韩国精品美女www爽爽爽视频| 日韩在线免费高清视频| 91极品女神在线| 久久九九精品99国产精品| 欧美野外wwwxxx| 欧美裸身视频免费观看| 欧美放荡办公室videos4k| 亚洲一区国产精品| 日韩精品亚洲精品| 欧美激情久久久久| 精品中文字幕在线| 久久久国产在线视频| 国产精品白嫩美女在线观看| 性色av一区二区咪爱| 国产精品免费视频久久久| 久久久av网站| 国产精品久久99久久| 欧美大肥婆大肥bbbbb| 91亚洲国产成人久久精品网站| 91色精品视频在线| 国产成人精品电影久久久| 91国产美女视频| 欧美成在线视频| 国产在线精品播放| 91精品国产91久久久久| 国产日韩专区在线| 国产在线精品自拍| 久久久久久久一区二区三区| 亚洲日本aⅴ片在线观看香蕉| 国产成人精彩在线视频九色| 深夜福利亚洲导航| 欧美成人精品在线| 91情侣偷在线精品国产| 日本精品久久久久影院| 91情侣偷在线精品国产| 国产一区欧美二区三区| 国产精品成人一区| 亚洲free性xxxx护士白浆| 亚洲精品ady| 欧美日韩高清区| 国产美女直播视频一区| 欧美性猛交xxxx乱大交蜜桃| 亚洲人成电影网站| www.久久草.com| 精品人伦一区二区三区蜜桃网站| 中文字幕亚洲欧美日韩2019| 欧美巨大黑人极品精男| 欧美极品在线播放| 国产婷婷97碰碰久久人人蜜臀| 欧美成在线视频| 亚洲第一精品夜夜躁人人爽| 亚洲国产精品久久久久秋霞不卡| 亚洲国产91精品在线观看| 欧美精品久久久久久久久| 亚洲人成网在线播放| xxx成人少妇69| 69av在线视频| 日韩欧美在线观看视频| 亚洲女在线观看| 国产精品91在线| 国产亚洲视频中文字幕视频| 国产精品99久久久久久久久久久久| 亚洲精品456在线播放狼人| 日韩中文在线中文网三级| 久久精视频免费在线久久完整在线看| 欧美大片第1页| 国产精品高潮在线| 免费av一区二区| 久久深夜福利免费观看| 国产一区二区三区高清在线观看| 九九热这里只有在线精品视|