UNPKG

@fanx/wxstore

Version:

wechat miniprogram store manager

662 lines (510 loc) 19.5 kB
Object.defineProperty(exports, "__esModule", { value: true }); exports.storePage = storePage; exports.storeComponent = storeComponent; exports["default"] = void 0; var _observer2 = _interopRequireDefault(require("./utils/observer")); var _diff = _interopRequireDefault(require("./utils/diff")); var _utils = require("./utils/utils"); var _instanceUtils = require("./utils/instanceUtils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var supportProxy = !!Proxy; // 是否支持Proxy var STORES = {}; // store 实例集 var storeId = 1; // store id var listenerId = 1; // 监听器id var WxStore = /*#__PURE__*/function () { function WxStore() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$state = _ref.state, state = _ref$state === void 0 ? {} : _ref$state, _ref$actions = _ref.actions, actions = _ref$actions === void 0 ? {} : _ref$actions, _ref$debug = _ref.debug, debug = _ref$debug === void 0 ? false : _ref$debug; _classCallCheck(this, WxStore); this._state = (0, _utils.deepClone)(state); if (supportProxy) { (0, _utils.defineStatic)(this, 'state', (0, _observer2["default"])((0, _utils.deepClone)(state), this._observer.bind(this))); // 监听对象变化 } else { this.state = (0, _utils.deepClone)(state); // state } this._id = storeId++; // store id this._binds = []; // 绑定的实例对象 this._diffObj = {}; // diff结果 this._observerList = []; // Proxy监听state this._listener = {}; // 监听state改变事件 this._debug = debug; // 开启debug模式后会输出没吃diff数据 (0, _utils.defineStatic)(this, 'actions', {}); // 行为方法 Object.keys(actions).forEach(function (key) { _this.actions[key] = actions[key].bind(_this); }); } /** * 监听 */ _createClass(WxStore, [{ key: "_observer", value: function _observer(keys, value) { var i = 0; var len = keys.length; // 判断是否覆盖已有,如果覆盖则移除旧的push新的 while (i < this._observerList.length) { var item = this._observerList[i]; if (item.keys.length >= len) { var match = true; for (var j = 0; j < len; j++) { if (keys[j] !== item.keys[j]) { match = false; break; } } if (match) { this._observerList.splice(i, 1); } else { i++; } } else { i++; } } this._observerList.push({ keys: keys, value: value }); } /** * 将state监听到的变化写入diff对象中用于最终的setData,且将变化同步到_state */ }, { key: "_observerSet", value: function _observerSet() { var _this2 = this; this._observerList.forEach(function (_ref2) { var keys = _ref2.keys, value = _ref2.value; value = (0, _utils.deepClone)(value); // 根据对象key 提取 state 与对于value比对 var keyStr = (0, _utils.toKeyStr)(keys, _this2._state); // 空对象不执行diff update操作 if ((0, _utils.noEmptyObject)(value, true)) { // 获取diffObj Object.assign(_this2._diffObj, (0, _diff["default"])(value, (0, _utils.getValue)(_this2._state, keys), keyStr)); } else { Object.assign(_this2._diffObj, _defineProperty({}, keyStr, value)); } // 同步到_state (0, _utils.setValue)(_this2._state, keys, value); }); this._observerList = []; } /** * 设置state * @param {*} obj set数据对象 */ }, { key: "_diffSet", value: function _diffSet() { // 获取diffObj Object.assign(this._diffObj, (0, _utils.deepClone)((0, _diff["default"])(this.state, this._state))); // 写入store state for (var key in this._diffObj) { var keys = (0, _utils.toKeys)(key); (0, _utils.setValue)(this._state, keys, this._diffObj[key]); } } /** * 更新视图 * @param {*} obj 更新对象 * @param {*} imm 是否立即更新视图 */ }, { key: "update", value: function update(obj, imm) { // 支持update写入更改state if ((0, _utils.type)(obj, _utils.OBJECT)) { for (var key in obj) { var keys = (0, _utils.toKeys)(key); (0, _utils.setValue)(this.state, keys, obj[key]); } } if (imm) { // 立即执行 return this._set(); } else { // 合并执行 return this._merge(); } } /** * 合并多次set */ }, { key: "_merge", value: function _merge() { var _this3 = this; // Promise实现合并set // eslint-disable-next-line no-return-assign return this._pendding = this._pendding || Promise.resolve().then(function () { return _this3._set(); }); } /** * 设置映射数据 */ }, { key: "_set", value: function _set() { var _this4 = this; return new Promise(function (resolve) { if (supportProxy) { // 支持Proxy的 _this4._observerSet(); } else { // 用于不支持Proxy _this4._diffSet(); } if ((0, _utils.noEmptyObject)(_this4._diffObj)) { var count = 0; var diffObj = _objectSpread({}, _this4._diffObj); // 实例更新 _this4._binds.forEach(function (that) { // 获取diffObj => 实例的新的diff数据 var obj = _this4._getMapData(that.__stores[_this4._id].stateMap); // set实例对象中 if ((0, _utils.noEmptyObject)(obj)) { count++; that.setData(obj, function () { count--; if (count <= 0) { resolve(diffObj); } }); } }); // 监听器回调 for (var id in _this4._listener) { // 监听 if (_this4._isChange(_this4._listener[id].map)) { // 执行回调 _this4._listener[id].fn(_this4._listener[id].map.map(function (key) { return (0, _utils.deepClone)((0, _utils.getValue)(_this4._state, (0, _utils.toKeys)(key))); })); } } if (count <= 0) { resolve(diffObj); } // debug diff 结果输出 _this4._debug && console.log('diff object:', _this4._diffObj); _this4._diffObj = {}; // 清空diff结果 } else { resolve({}); } delete _this4._pendding; // 清除 }); } /** * 绑定对象 * @param {*} that 实例Page/Component * @param {*} map 实例data => state 的映射map * @param {*} extend bind时映射到data的扩展字段 */ }, { key: "bind", value: function bind(that, map) { var extend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // 必须为实例对象 if (!(0, _utils.type)(that, _utils.OBJECT)) { console.warn('[wxStore] check bind this'); return; } // 必须是obj或者arr if (!(0, _utils.type)(map, _utils.OBJECT) && !(0, _utils.type)(map, _utils.ARRAY)) { console.warn('[wxStore] check bind stateMap'); map = {}; } var stateMap = (0, _utils.reverse)(map); this._bind(that, stateMap, extend); } /** * 绑定对象 * @param {*} that 实例Page/Component * @param {*} stateMap state => 实例data 的映射map * @param {*} extend bind时映射到data的扩展字段 */ }, { key: "_bind", value: function _bind(that, stateMap) { var extend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // 必须是obj或者arr if (!(0, _utils.type)(stateMap, _utils.OBJECT) && !(0, _utils.type)(stateMap, _utils.ARRAY)) { console.warn('[wxStore] check bind stateMap'); stateMap = {}; } // 获取state=>实例data的指向 var id = this._id; var setter = (0, _diff["default"])(Object.assign(setData(stateMap, this._state), extend), that.data); that.setData(setter); // 执行set that.__stores = (0, _utils.type)(that.__stores, _utils.OBJECT) ? that.__stores : {}; // 初始化实例对象上的状态映射表 // 映射对象写入实例对象 if (that.__stores[id]) { Object.assign(that.__stores[id].stateMap, stateMap); } else { that.__stores[id] = { stateMap: stateMap, store: this }; } !this._binds.find(function (item) { return item === that; }) && this._binds.push(that); // 实例写入this._binds数组中,用于update找到实例对象 STORES[id] || (STORES[id] = this); // 已bind store 存入STORES集合 } /** * 解除绑定 * @param {*} that 实例Page/Component */ }, { key: "unBind", value: function unBind(that) { that.__stores && delete that.__stores[this._id]; // 清除状态管理对象映射对象 // 移除实例绑定 for (var i = 0; i < this._binds.length; i++) { if (this._binds[i] === that) { this._binds.splice(i, 1); break; } } // bind列表空时,在STORES删除store if (!this._binds.length) { delete STORES[this._id]; } } /** * 监听状态改变 * @param {*} map 监听的数据映射 * @param {*} fn 监听回调 */ }, { key: "on", value: function on(map, fn, that) { if ((0, _utils.type)(map, _utils.STRING)) { // eslint-disable-next-line no-useless-escape map = map.split(/\s*\,\s*/g); } // map必须为obj或者arr 且fn必须为function if (!(0, _utils.noEmptyObject)(map, true) || !(0, _utils.type)(fn, _utils.FUNCTION)) { console.warn('[wxStore] check on params'); return; } // 获取监听state的映射 map = (0, _utils.deepClone)(map); // 监听器id var id = listenerId++; // 监听器数据保存到this._listener中 this._listener[id] = { map: map, fn: fn }; if ((0, _utils.type)(that, _utils.OBJECT)) { that.__listener = (0, _utils.type)(that.__listener, _utils.OBJECT) ? that.__listener : {}; that.__listener[id] = this; } // id用于remove return id; } /** * 移除监听状态改变 * @param {*} id listener的id */ }, { key: "remove", value: function remove(id) { if (this._listener[id]) { delete this._listener[id]; } } /** * 根据具体diff 及 映射map 获得最终setData对象 * @param {*} map 映射map */ }, { key: "_getMapData", value: function _getMapData(map) { if (!(0, _utils.noEmptyObject)(map)) return {}; var obj = {}; // diff结果与映射的双重比对 var reg = RegExp("^(".concat(Object.keys(map).join('|'), ")((?=(?:\\.|\\[))|$)")); for (var key in this._diffObj) { var match = false; var newKey = key.replace(reg, function (s) { match = true; return map[s] || s; }); if (match) { obj[newKey] = this._diffObj[key]; } } return obj; } /** * 监听的对象是否修改 * @param {*} map */ }, { key: "_isChange", value: function _isChange(map) { // diff结果与映射的双重比对 var reg = RegExp("^(".concat(map.join('|'), ")((?=(?:\\.|\\[))|$)")); for (var key in this._diffObj) { if (key.match(reg)) { return true; } } return false; } /** * 通过字符串key获取value */ }, { key: "getState", value: function getState(key) { if ((0, _utils.type)(key, _utils.STRING)) { return (0, _utils.deepClone)((0, _utils.getValue)(this._state, (0, _utils.toKeys)(key))); } } }]); return WxStore; }(); /** * 挂载 * @param {*} ops 实例配置 */ exports["default"] = WxStore; function Attached(ops) { var _this5 = this; ops.stateMap = ops.stateMap || {}; ops.store = ops.store || {}; // stores 必须为数组 if ((0, _utils.type)(ops.stores, _utils.ARRAY)) { ops.stores.forEach(function () { var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // store必须为WxStore对象、stateMap必须为Object或Array var store = item.store, stateMap = item.stateMap, _rstateMap = item._rstateMap; if (store instanceof WxStore && (0, _utils.noEmptyObject)(stateMap, true)) { _rstateMap ? store._bind(_this5, _rstateMap) : store.bind(_this5, stateMap); } }); } // store必须为对象、stateMap必须为Object或Array if ((0, _utils.type)(ops.store, _utils.OBJECT) && ((0, _utils.type)(ops.stateMap, _utils.OBJECT) || (0, _utils.type)(ops.stateMap, _utils.ARRAY))) { var _ref3 = this.properties || {}, _ref3$STOREID = _ref3.STOREID, STOREID = _ref3$STOREID === void 0 ? 0 : _ref3$STOREID; // store 如果是Wxstore的实例则直接使用,否则使用id为STOREID的store,ops.fixed === true 使用页面级store, 否则通过store配置生产新的store this.store = ops.store instanceof WxStore ? ops.store : STORES[STOREID] || !ops.fixed && (0, _instanceUtils.getCurrentPage)(this).store || new WxStore(ops.store); // 传入已经是WxStore实例则直接赋值,否者实例化 var extend = ops.fixed ? { STOREID: this.store._id } : {}; ops._rstateMap ? this.store._bind(this, this._rstateMap, extend) : this.store.bind(this, ops.stateMap, extend); // 绑定是不初始化data、在实例生产前已写入options中 } } /** * 取消挂载 */ function Detached() { // 解除this上的listener的绑定 if ((0, _utils.noEmptyObject)(this.__listener)) { for (var id in this.__listener) { this.__listener[id].remove(id); } delete this.__listener; } // 解除this上的store的绑定 if ((0, _utils.noEmptyObject)(this.__stores)) { for (var _id in this.__stores) { this.__stores[_id].store.unBind(this); } delete this.__stores; } delete this.store; // 删除store } /** * 重写Page方法,提供自动绑定store自定移除store方法 * @param {*} ops 页面初始化配置 */ function storePage(ops) { initData(ops); // 初始化data、作用是给data里面填入store中的默认state // 重写onLoad var onLoad = ops.onLoad; ops.onLoad = function () { ops.fixed = true; Attached.call(this, ops); (0, _instanceUtils.pushTabPage)(this); (0, _utils.type)(onLoad, _utils.FUNCTION) && onLoad.apply(this, [].slice.call(arguments)); }; // 重写onUnload var onUnload = ops.onUnload; ops.onUnload = function () { (0, _utils.type)(onUnload, _utils.FUNCTION) && onUnload.apply(this, [].slice.call(arguments)); // 执行卸载操作 (0, _instanceUtils.shiftTabPage)(this); Detached.call(this); }; Page(ops); } /** * 重写Component方法,提供自动绑定store自定移除store方法 * @param {*} ops 组件初始化配置 */ function storeComponent(ops) { initData(ops); // 初始化data、作用是给relateddata里面填入store中的默认state ops.properties = (0, _utils.type)(ops.properties, _utils.OBJECT) ? ops.properties : {}; Object.assign(ops.properties, { STOREID: Number }); var name = ops.fixed ? 'attached' : 'ready'; var lts = ops.lifetimes && ops.lifetimes[name] ? ops.lifetimes : ops; // 重写ready var init = lts[name]; lts[name] = function () { Attached.call(this, ops); (0, _utils.type)(init, _utils.FUNCTION) && init.apply(this, [].slice.call(arguments)); }; lts = ops.lifetimes && ops.lifetimes.detached ? ops.lifetimes : ops; // 重写detached var detached = lts.detached; lts.detached = function () { (0, _utils.type)(detached, _utils.FUNCTION) && detached.apply(this, [].slice.call(arguments)); // 执行卸载操作 Detached.call(this); }; Component(ops); } /** * diff */ exports.diff = _diff["default"]; /** * 初始化数据 * @param {*} map * @param {*} data */ function setData(map, data) { var obj = {}; // 初始化实例的data if ((0, _utils.noEmptyObject)(map) && (0, _utils.type)(data, _utils.OBJECT)) { // 在初始化实例data使用 for (var key in map) { var keys = (0, _utils.toKeys)(key); obj[map[key]] = (0, _utils.deepClone)((0, _utils.getValue)(data, keys)); } } return obj; } /** * 初始化数据 * @param {*} map * @param {*} data */ function initData(ops) { var data = {}; if ((0, _utils.type)(ops.stores, _utils.ARRAY)) { ops.stores = ops.stores.map(function (s) { if ((0, _utils.type)(s.store, _utils.OBJECT) && (0, _utils.noEmptyObject)(s.stateMap, true)) { s._rstateMap = (0, _utils.reverse)(s.stateMap); Object.assign(data, setData(s._rstateMap, s.store._state || s.store.state)); } return s; }); } if ((0, _utils.type)(ops.store, _utils.OBJECT) && (0, _utils.noEmptyObject)(ops.stateMap, true)) { ops._rstateMap = (0, _utils.reverse)(ops.stateMap); Object.assign(data, setData(ops._rstateMap, ops.store._state || ops.store.state)); } ops.data = (0, _utils.type)(ops.data, _utils.OBJECT) ? ops.data : {}; Object.assign(ops.data, data); return data; }