init
This commit is contained in:
1
node_modules/spa-custom-hooks/lib/spa-custom-hooks.js
generated
vendored
Normal file
1
node_modules/spa-custom-hooks/lib/spa-custom-hooks.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/spa-custom-hooks/lib/spa-custom-hooks.mjs
generated
vendored
Normal file
1
node_modules/spa-custom-hooks/lib/spa-custom-hooks.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
178
node_modules/spa-custom-hooks/lib/spa-custom-hooks/custom-hook.js
generated
vendored
Normal file
178
node_modules/spa-custom-hooks/lib/spa-custom-hooks/custom-hook.js
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
import { Hooks, nativeHooks, getDiyHooks } from './hooks.js';
|
||||
import { getVal, getStore } from './utils.js';
|
||||
|
||||
/**
|
||||
* @Author 鹅鹅鹅
|
||||
* @DateTime 2023-12-01
|
||||
* @description 自定义钩子
|
||||
*/
|
||||
export default class customHook {
|
||||
constructor({ instance, options, pageHooks, instanceType, initHookName }) {
|
||||
// 页面实例、原生钩子对象
|
||||
this.instance = instance;
|
||||
// 实例类型 app,page,component
|
||||
this.instanceType = instanceType;
|
||||
// 进行实例化的钩子名称
|
||||
this.initHookName = initHookName;
|
||||
// 是否是组件
|
||||
this.isComponent = instanceType === 'component';
|
||||
// 页面内需要处理的所有钩子构成和函数执行状态
|
||||
this.customHooks = {};
|
||||
// 页面内需要处理的所有钩子数组
|
||||
this.customHookArr = [];
|
||||
// 所有钩子对象,注册的所有钩子的hookEntity类集合
|
||||
this.hook = {};
|
||||
// url里的参数
|
||||
this.options = options || {};
|
||||
// 钩子对象
|
||||
this.pageHooks = pageHooks;
|
||||
// 自定义的属性监听钩子
|
||||
this.diyHooks = getDiyHooks();
|
||||
this.init();
|
||||
//检测是否有需要立即触发的钩子
|
||||
this.triggerHook();
|
||||
}
|
||||
init() {
|
||||
// 提出需要注入的自定义钩子
|
||||
let hook = Hooks(this, this.initHookName);
|
||||
// 当前实例支持的所有钩子
|
||||
this.presetHooksName = Object.keys(hook);
|
||||
this.hook = hook;
|
||||
let pageHooks = this.pageHooks;
|
||||
// 钩子对象在自身还是原型链
|
||||
let oneself = pageHooks.hasOwnProperty('beforeCreate') || pageHooks.hasOwnProperty('onReady');
|
||||
pageHooks = oneself ? pageHooks : pageHooks['__proto__'];
|
||||
if (this.isComponent) {
|
||||
// 把lifetimes和pageLifetimes合并过来一起处理
|
||||
Object.assign(pageHooks, pageHooks.lifetimes, pageHooks.pageLifetimes);
|
||||
}
|
||||
// 过滤钩子对象、分析钩子构成
|
||||
let { customHookArr, hookInscape } = this.filterHooks(pageHooks);
|
||||
// 单独处理每个钩子
|
||||
customHookArr.forEach((e) => {
|
||||
this.customHooks[e] = {
|
||||
// 此钩子实体函数
|
||||
callback: pageHooks[e].bind(this.instance),
|
||||
// 此钩子构成
|
||||
inscape: hookInscape[e],
|
||||
// 此钩子是否已执行
|
||||
execute: false,
|
||||
// 决定执行顺序的累加权重值,小的在前先执行
|
||||
weightValue: hookInscape[e].reduce((total, hookKey) => {
|
||||
return (total += this.hook[hookKey]?.weightValue || 0);
|
||||
}, 0),
|
||||
};
|
||||
});
|
||||
// 按weightValue进行排序
|
||||
this.customHookArr = customHookArr.sort((a, b) => {
|
||||
return this.customHooks[a].weightValue - this.customHooks[b].weightValue;
|
||||
});
|
||||
// await Promise.resolve();
|
||||
Object.keys(this.hook).forEach((e) => this.hook[e].init());
|
||||
}
|
||||
/**
|
||||
* 过滤出钩子对象
|
||||
* @params Object<key,function> 页面所有钩子对象列表
|
||||
* return {
|
||||
* customHookArr Array<string> 自定义钩子数组
|
||||
* hookInscape Object<key,Array<string>> 自定义钩子构成
|
||||
* }
|
||||
*/
|
||||
filterHooks(option) {
|
||||
// 各钩子和包含的所有已注册单独钩子构成
|
||||
let hookInscape = {};
|
||||
// 筛选出来用到的hook实例
|
||||
const filterHook = {};
|
||||
const customHookArr = Object.keys(option).filter((e) => {
|
||||
// 不符合规则的钩子不予处理
|
||||
let hookArr = this.getHookArr(e);
|
||||
if (hookArr.length) {
|
||||
//过滤掉未注册的钩子
|
||||
hookInscape[e] = hookArr.filter((h) => {
|
||||
if (this.hook[h]) {
|
||||
filterHook[h] = this.hook[h];
|
||||
return true;
|
||||
}
|
||||
console.warn(
|
||||
`[custom-hook 错误声明警告] "${h}"钩子未注册,意味着"${e}"可能永远不会执行,请先注册此钩子再使用,文档:https://github.com/1977474741/spa-custom-hooks#-diyhooks对象说明`
|
||||
);
|
||||
return false;
|
||||
});
|
||||
//格式 + 是否注册的效验
|
||||
return e == 'on' + hookArr.join('') && hookInscape[e].length == hookArr.length;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// 只保留用到的hook实例
|
||||
this.hook = filterHook;
|
||||
return {
|
||||
customHookArr,
|
||||
hookInscape,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 检测是否有需要触发的钩子
|
||||
* @params <string> 本次变化的钩子key
|
||||
*/
|
||||
triggerHook(hitKey) {
|
||||
this.customHookArr.forEach((name) => {
|
||||
let customHook = this.customHooks[name];
|
||||
let meet = customHook.inscape.every((e) => this.hook[e] && this.checkHookHit(this.hook[e]));
|
||||
if (meet && !customHook.execute) {
|
||||
customHook.execute = true;
|
||||
this.customHooks[name]['callback'](this.options);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 清除关于本次destroy钩子的所有包含此钩子的执行状态
|
||||
* @params <string> 要清除的钩子名称
|
||||
*/
|
||||
resetExecute(destroyHookName) {
|
||||
this.customHookArr.forEach((pageHookName) => {
|
||||
let customHook = this.customHooks[pageHookName];
|
||||
if (customHook.inscape.find((hookName) => destroyHookName === this.hook[hookName]?.destroy)) {
|
||||
customHook.execute = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 检验此钩子是否满足命中条件
|
||||
* @param hookEntity实例
|
||||
* return <boolean> 是否满足
|
||||
*/
|
||||
checkHookHit(hookEntity) {
|
||||
if (hookEntity.watchKey) {
|
||||
//注意:instance对象必须从传进来的实体里拿,不能this.instance
|
||||
let val = getVal(getStore(hookEntity.__customhook.instance).state, hookEntity.watchKey);
|
||||
return hookEntity.onUpdate ? hookEntity.onUpdate(val) : val;
|
||||
} else {
|
||||
return hookEntity.hit;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取组合钩子包含的所有钩子(包含多于一个钩子 || 单个自定义属性钩子)、是的话返回钩子构成
|
||||
* @param <string> 钩子名称
|
||||
* return Array<string> 钩子构成
|
||||
*/
|
||||
getHookArr(name) {
|
||||
if (name.indexOf('on') == -1) return [];
|
||||
const hookArr = this.splitHook(name),
|
||||
diyHooks = this.diyHooks;
|
||||
return hookArr.length > 1 || diyHooks.indexOf(hookArr[0]) != -1 ? hookArr : [];
|
||||
}
|
||||
/**
|
||||
* 分析组合钩子构成
|
||||
* @param <string> 组合钩子名称
|
||||
* return Array<string> 钩子构成数组
|
||||
*/
|
||||
splitHook(name) {
|
||||
name = name.replace('on', '');
|
||||
// 将钩子数组按照长度进行降序排序,以确保匹配最长的字符串优先
|
||||
this.presetHooksName.sort((a, b) => b.length - a.length);
|
||||
// 使用正则表达式将钩子数组中的每个元素都转换为对应的捕获组,然后通过join函数连接起来
|
||||
let regex = new RegExp('(' + this.presetHooksName.join('|') + ')', 'g');
|
||||
// 使用split函数根据正则表达式对组合钩子进行分割并过滤掉无效的部分
|
||||
return name.split(regex).filter((e) => this.hook[e]);
|
||||
}
|
||||
}
|
||||
64
node_modules/spa-custom-hooks/lib/spa-custom-hooks/hook-entity.js
generated
vendored
Normal file
64
node_modules/spa-custom-hooks/lib/spa-custom-hooks/hook-entity.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @Author 鹅鹅鹅
|
||||
* @description 单个hook处理工厂
|
||||
*/
|
||||
import { getStore, getVal } from './utils.js';
|
||||
export default class hookEntity {
|
||||
constructor({ customhook, name, destroy, hit = false, watchKey, onUpdate, type, weightValue }) {
|
||||
// 钩子名
|
||||
this.name = name;
|
||||
// 相反钩子名
|
||||
this.destroy = destroy;
|
||||
// 钩子类型 app、page、component
|
||||
this.type = type;
|
||||
// hit是在是生命周期钩子的情况下才有用,属性监听钩子是检测时(triggerHook)实时判断的,没有用hit属性
|
||||
this.hit = hit;
|
||||
// 需要监听的key
|
||||
this.watchKey = watchKey;
|
||||
// 权重值,决定了和其他钩子同时满足条件时执行先后顺序
|
||||
this.weightValue = weightValue;
|
||||
// 是否已经初始化
|
||||
this.initFlag = false;
|
||||
// 属性监听回调
|
||||
this.onUpdate = onUpdate;
|
||||
this.__customhook = customhook;
|
||||
}
|
||||
init() {
|
||||
if (this.initFlag) return;
|
||||
if (this.watchKey) {
|
||||
this.unwatchFn = this.watchAttr((success) => {
|
||||
this[success ? 'cycleStart' : 'cycleEnd']();
|
||||
});
|
||||
}
|
||||
this.initFlag = true;
|
||||
}
|
||||
cycleStart() {
|
||||
if (this.hit) return;
|
||||
this.hit = true;
|
||||
this.__customhook && this.__customhook.triggerHook(this.name);
|
||||
}
|
||||
cycleEnd() {
|
||||
if (!this.hit) return;
|
||||
this.hit = false;
|
||||
this.__customhook && this.destroy && this.__customhook.resetExecute(this.destroy);
|
||||
}
|
||||
watchAttr(cb) {
|
||||
try {
|
||||
const that = this;
|
||||
const store = getStore(this.__customhook.instance);
|
||||
const unwatchFn = store.watch(
|
||||
(state) => {
|
||||
return getVal(state, that.watchKey);
|
||||
},
|
||||
(val, oldval) => {
|
||||
cb(that.onUpdate ? that.onUpdate(val, oldval) : val);
|
||||
},
|
||||
{
|
||||
//兼容mini-polyfill
|
||||
watchKey: that.watchKey,
|
||||
}
|
||||
);
|
||||
return unwatchFn;
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
232
node_modules/spa-custom-hooks/lib/spa-custom-hooks/hooks.js
generated
vendored
Normal file
232
node_modules/spa-custom-hooks/lib/spa-custom-hooks/hooks.js
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
import hookEntity from './hook-entity.js';
|
||||
// 注册的自定义钩子
|
||||
let diyHooks = {};
|
||||
|
||||
// 需要mixin的原生钩子
|
||||
const nativeHooks = [
|
||||
// vue
|
||||
'beforeCreate',
|
||||
'created',
|
||||
'onPageShow',
|
||||
'beforeMount',
|
||||
'mounted',
|
||||
'activated',
|
||||
'onPageHide',
|
||||
'deactivated',
|
||||
'beforeDestroy',
|
||||
'destroyed',
|
||||
// app和page
|
||||
'onLaunch',
|
||||
'onLoad',
|
||||
'onShow',
|
||||
'onReady',
|
||||
'onHide',
|
||||
'onUnload',
|
||||
];
|
||||
// 原生组件钩子
|
||||
const componentHooks = ['onInit', 'created', 'attached', 'ready', 'didMount', 'detached', 'didUnmount'];
|
||||
const lifetimesHooks = ['created', 'attached', 'ready', 'detached'];
|
||||
const pageLifetimesHooks = ['show', 'hide', 'routeDone'];
|
||||
// 原生所有钩子
|
||||
const nativeAllHooks = [...new Set([...nativeHooks, ...componentHooks])];
|
||||
/**
|
||||
* 输入hooks配置项,所有hook经过hookEntity处理,输出hookEntity对象列表
|
||||
* @param1 <customhook>实例化对象
|
||||
* @param2 <string> 初始化的钩子名
|
||||
* return Object<key,hookEntity> 所有注册的hook对应的hookEntity对象列表
|
||||
*/
|
||||
const Hooks = (customhook, initHookName) =>
|
||||
Object.keys(diyHooks).reduce(
|
||||
(hooks, key) => {
|
||||
const diyHook = diyHooks[key];
|
||||
diyHook.customhook = customhook;
|
||||
return (hooks[key] = new hookEntity(diyHook)) && hooks;
|
||||
},
|
||||
{
|
||||
// vue钩子
|
||||
BeforeCreate: new hookEntity({
|
||||
customhook,
|
||||
name: 'BeforeCreate',
|
||||
destroy: 'destroyed',
|
||||
hit: true,
|
||||
weightValue: 2,
|
||||
}),
|
||||
BeforeMount: new hookEntity({
|
||||
customhook,
|
||||
name: 'beforeMount',
|
||||
destroy: 'destroyed',
|
||||
weightValue: 4,
|
||||
}),
|
||||
PageShow: new hookEntity({
|
||||
customhook,
|
||||
name: 'onPageShow',
|
||||
destroy: 'onPageHide',
|
||||
weightValue: 4.1,
|
||||
}),
|
||||
Mounted: new hookEntity({
|
||||
customhook,
|
||||
name: 'mounted',
|
||||
destroy: 'destroyed',
|
||||
weightValue: 5,
|
||||
}),
|
||||
Activated: new hookEntity({
|
||||
customhook,
|
||||
name: 'activated',
|
||||
destroy: 'deactivated',
|
||||
weightValue: 6,
|
||||
}),
|
||||
PageHide: new hookEntity({
|
||||
customhook,
|
||||
name: 'onPageHide',
|
||||
destroy: 'onPageShow',
|
||||
weightValue: 6.1,
|
||||
}),
|
||||
Deactivated: new hookEntity({
|
||||
customhook,
|
||||
name: 'deactivated',
|
||||
destroy: 'activated',
|
||||
weightValue: 7,
|
||||
}),
|
||||
// 兼容页面的钩子和组件的钩子名相似的情况,比如各种小程序的页面是onShow,组件却是show,但他们的key在这里都是Show,为了防止key冲突,故而加判断分开注册,保证key的唯一性,也统一了页面和组件钩子的声明方式
|
||||
...(!customhook.isComponent
|
||||
? {
|
||||
Launch: new hookEntity({
|
||||
customhook,
|
||||
name: 'onLaunch',
|
||||
destroy: 'onUnload',
|
||||
hit: true,
|
||||
weightValue: 3,
|
||||
}),
|
||||
Created: new hookEntity({
|
||||
customhook,
|
||||
name: 'created',
|
||||
destroy: 'destroyed',
|
||||
hit: initHookName === 'created',
|
||||
weightValue: 3,
|
||||
}),
|
||||
Load: new hookEntity({
|
||||
customhook,
|
||||
name: 'onLoad',
|
||||
destroy: 'onUnload',
|
||||
hit: initHookName === 'onLoad',
|
||||
weightValue: 4,
|
||||
}),
|
||||
Ready: new hookEntity({
|
||||
customhook,
|
||||
name: 'onReady',
|
||||
destroy: 'onUnload',
|
||||
weightValue: 5,
|
||||
}),
|
||||
Show: new hookEntity({
|
||||
customhook,
|
||||
name: 'onShow',
|
||||
destroy: 'onHide',
|
||||
weightValue: 6,
|
||||
}),
|
||||
Hide: new hookEntity({
|
||||
customhook,
|
||||
name: 'onHide',
|
||||
destroy: 'onShow',
|
||||
weightValue: 7,
|
||||
}),
|
||||
}
|
||||
: {
|
||||
// 原生小程序组件 包含的钩子
|
||||
Init: new hookEntity({
|
||||
customhook,
|
||||
name: 'onInit',
|
||||
destroy: 'didUnmount',
|
||||
hit: initHookName === 'onInit',
|
||||
weightValue: 2,
|
||||
}),
|
||||
Created: new hookEntity({
|
||||
customhook,
|
||||
name: 'created',
|
||||
destroy: 'detached',
|
||||
hit: initHookName === 'created',
|
||||
weightValue: 3,
|
||||
}),
|
||||
Attached: new hookEntity({
|
||||
customhook,
|
||||
name: 'attached',
|
||||
destroy: 'detached',
|
||||
weightValue: 4,
|
||||
}),
|
||||
Show: new hookEntity({
|
||||
customhook,
|
||||
name: 'show',
|
||||
destroy: 'hide',
|
||||
weightValue: 5,
|
||||
}),
|
||||
DidMount: new hookEntity({
|
||||
customhook,
|
||||
name: 'didMount',
|
||||
destroy: 'didUnmount',
|
||||
hit: initHookName === 'didMount',
|
||||
weightValue: 6,
|
||||
}),
|
||||
Ready: new hookEntity({
|
||||
customhook,
|
||||
name: 'ready',
|
||||
destroy: 'detached',
|
||||
weightValue: 7,
|
||||
}),
|
||||
// 微信小程序组件所在页面的生命周期
|
||||
RouteDone: new hookEntity({
|
||||
customhook,
|
||||
name: 'routeDone',
|
||||
destroy: 'detached',
|
||||
weightValue: 8,
|
||||
}),
|
||||
Hide: new hookEntity({
|
||||
customhook,
|
||||
name: 'hide',
|
||||
destroy: 'show',
|
||||
weightValue: 9,
|
||||
}),
|
||||
Detached: new hookEntity({
|
||||
customhook,
|
||||
name: 'detached',
|
||||
destroy: 'attached',
|
||||
weightValue: 10,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const init = (hooks) => (diyHooks = hooks);
|
||||
|
||||
/**
|
||||
* 获取所有自定义钩子
|
||||
* return Array<string> diy钩子数组
|
||||
*/
|
||||
const getDiyHooks = () => Object.keys(diyHooks);
|
||||
|
||||
/**
|
||||
* 手动命中某属性钩子-待开发
|
||||
* @param1 <string> 单个钩子名
|
||||
* @param2 <string> 要改变的状态
|
||||
*/
|
||||
const setHit = (name, state) => {
|
||||
Hooks()[name][state ? 'cycleStart' : 'cycleEnd']();
|
||||
};
|
||||
|
||||
/**
|
||||
* 使用js监听属性钩子-待开发
|
||||
* @param1 <string> 钩子名、这里只允许属性监听钩子
|
||||
* @param2 <function> 回调函数
|
||||
*/
|
||||
const on = (name, cb) => { };
|
||||
|
||||
export {
|
||||
Hooks,
|
||||
getDiyHooks,
|
||||
nativeAllHooks,
|
||||
lifetimesHooks,
|
||||
pageLifetimesHooks,
|
||||
nativeHooks,
|
||||
componentHooks,
|
||||
init,
|
||||
setHit,
|
||||
on,
|
||||
};
|
||||
16
node_modules/spa-custom-hooks/lib/spa-custom-hooks/index.js
generated
vendored
Normal file
16
node_modules/spa-custom-hooks/lib/spa-custom-hooks/index.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as init from './init.js';
|
||||
import { setHit } from './hooks.js';
|
||||
import * as polyfill from './mini-polyfill.js';
|
||||
const install = function () {
|
||||
if (arguments.length < 3) {
|
||||
// 小程序架构,使用垫片
|
||||
init.install(polyfill.vue, arguments[0], polyfill.store, arguments[1] || 'globalData');
|
||||
} else {
|
||||
// vue架构
|
||||
init.install(...arguments);
|
||||
}
|
||||
};
|
||||
export default {
|
||||
install,
|
||||
setHit,
|
||||
};
|
||||
158
node_modules/spa-custom-hooks/lib/spa-custom-hooks/init.js
generated
vendored
Normal file
158
node_modules/spa-custom-hooks/lib/spa-custom-hooks/init.js
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
import customHook from './custom-hook.js';
|
||||
import * as hooks from './hooks.js';
|
||||
import { getVal, setStore } from './utils.js';
|
||||
const userAgentKeys = {
|
||||
'vue-h5': {
|
||||
// 组件的hook对象
|
||||
hooksKey: '$options',
|
||||
// 用来初始化的hook
|
||||
initHook: 'beforeCreate',
|
||||
// 是否支持组件、暂废弃
|
||||
supportComponent: true,
|
||||
isPage(pageHooks) {
|
||||
return pageHooks._compiled && this.supportComponent;
|
||||
},
|
||||
},
|
||||
'vue-miniprogram': {
|
||||
hooksKey: '$options',
|
||||
initHook: 'beforeCreate',
|
||||
supportComponent: true,
|
||||
isPage() {
|
||||
return this.supportComponent;
|
||||
},
|
||||
},
|
||||
miniprogram: {
|
||||
name: 'miniprogram',
|
||||
hooksKey: '',
|
||||
initHook: 'onLoad',
|
||||
initHookApp: 'onLaunch',
|
||||
initHookComponentAlipay: 'didMount',
|
||||
initHookComponentAlipayInit: 'onInit',
|
||||
initHookComponentWx: 'created',
|
||||
initHookComponentLifetimes: 'created',
|
||||
supportComponent: true,
|
||||
isPage() {
|
||||
return this.supportComponent;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let BASE = userAgentKeys['vue-miniprogram'];
|
||||
const install = (vue, params, store, storeKey) => {
|
||||
//基于mpvue框架特殊处理,避免created的bug
|
||||
if (vue.mpvueVersion) {
|
||||
BASE.initHook = 'onLoad';
|
||||
} else if (vue.userAgentKey) {
|
||||
// 垫片里指定userAgentKey,根据参数来判断vue架构||原生小程序
|
||||
BASE = userAgentKeys[vue.userAgentKey];
|
||||
}
|
||||
setStore(store);
|
||||
hooks.init(params);
|
||||
vue.mixin({
|
||||
// 监听所有原生钩子,改变对应状态
|
||||
...hooksMutation(hooks.nativeAllHooks),
|
||||
// vue初始化钩子beforeCreate
|
||||
[BASE.initHook](options) {
|
||||
hookInit.call(this, options, 'page', undefined, BASE.initHook);
|
||||
},
|
||||
...(BASE.name === 'miniprogram'
|
||||
? {
|
||||
// 所有小程序App初始化钩子onLaunch
|
||||
[BASE.initHookApp](options) {
|
||||
hookInit.call(this, options, 'app', undefined, BASE.initHookApp);
|
||||
},
|
||||
//微信小程序组件初始化钩子created
|
||||
[BASE.initHookComponentWx](optionProperties, options) {
|
||||
hookInit.call(this, options, 'component', optionProperties, BASE.initHookComponentWx);
|
||||
},
|
||||
//支付宝小程序组件初始化钩子onInit
|
||||
[BASE.initHookComponentAlipayInit](optionProperties, options) {
|
||||
hookInit.call(this, options, 'component', optionProperties, BASE.initHookComponentAlipayInit);
|
||||
},
|
||||
//支付宝小程序组件初始化钩子didMount
|
||||
//兼容支付宝小程序普通和component2模式,init、created、didMount都有可能做初始化
|
||||
[BASE.initHookComponentAlipay](optionProperties, options) {
|
||||
componentHookTriggered.call(this, optionProperties, options, BASE.initHookComponentAlipay);
|
||||
},
|
||||
// 小程序原生组件api混入
|
||||
lifetimes: {
|
||||
...hooksMutation(hooks.lifetimesHooks),
|
||||
//支付宝小程序组件初始化钩子created、在lifetimes为true并且未开启component2时作为初始化
|
||||
[BASE.initHookComponentLifetimes](optionProperties, options) {
|
||||
componentHookTriggered.call(this, optionProperties, options, BASE.initHookComponentLifetimes);
|
||||
},
|
||||
},
|
||||
pageLifetimes: {
|
||||
...hooksMutation(hooks.pageLifetimesHooks),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
// 钩子执行后,初始化 || 改钩子状态
|
||||
function componentHookTriggered(optionProperties, options, hookName) {
|
||||
// 已经初始化的修改内部钩子状态,否则走初始化逻辑
|
||||
if (this.customHook) {
|
||||
updateHookState.call(this, options, hookName);
|
||||
return;
|
||||
}
|
||||
hookInit.call(this, options, 'component', optionProperties, hookName);
|
||||
}
|
||||
// 初始化,实例化custom-hook-spa
|
||||
function hookInit(options, instanceType, optionProperties, initHookName) {
|
||||
if (this.customHook) return;
|
||||
// 入口文件特殊处理
|
||||
let pageHooks = getVal(this, BASE['hooksKey']);
|
||||
// 过滤掉非业务组件
|
||||
if (BASE.isPage(pageHooks)) {
|
||||
// 兼容非vuex环境
|
||||
if (!store.state && storeKey) {
|
||||
store.state = this[storeKey] || storeKey;
|
||||
}
|
||||
const isComponent = instanceType === 'component';
|
||||
Object.defineProperty(this, 'customHook', {
|
||||
value: new customHook({
|
||||
instance: this,
|
||||
options,
|
||||
pageHooks: isComponent ? optionProperties : pageHooks,
|
||||
instanceType,
|
||||
initHookName: initHookName,
|
||||
}),
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 监听所有钩子并修改状态
|
||||
function hooksMutation(hookNames) {
|
||||
return hookNames.reduce(
|
||||
(hooks, hookName) =>
|
||||
(hooks[hookName] = function (options) {
|
||||
updateHookState.call(this, options, hookName);
|
||||
}) && hooks,
|
||||
{}
|
||||
);
|
||||
}
|
||||
// 更新已经存在的实例化custom-hook-spa对应钩子状态
|
||||
function updateHookState(options, hookName) {
|
||||
//没有创建customHook不作处理
|
||||
if (typeof this.customHook != 'object' && typeof this.customHook != null) return;
|
||||
//customHook里没有自定义钩子不作处理
|
||||
if (!this.customHook.customHookArr.length) return;
|
||||
if (options && Object.keys(options).length > 0) {
|
||||
this.customHook.options = options;
|
||||
}
|
||||
const hooks = this.customHook.hook;
|
||||
const isDestroy = ['beforeDestroy', 'destroyed', 'onUnload', 'didUnmount', 'detached'].includes(hookName);
|
||||
for (let k in hooks) {
|
||||
const hook = hooks[k];
|
||||
if (hook.name == hookName) {
|
||||
hook.cycleStart();
|
||||
} else if (hook.destroy == hookName) {
|
||||
hook.cycleEnd();
|
||||
}
|
||||
isDestroy && hook.unwatchFn?.();
|
||||
}
|
||||
isDestroy && delete this.customHook;
|
||||
}
|
||||
};
|
||||
export { install, BASE };
|
||||
180
node_modules/spa-custom-hooks/lib/spa-custom-hooks/mini-polyfill.js
generated
vendored
Normal file
180
node_modules/spa-custom-hooks/lib/spa-custom-hooks/mini-polyfill.js
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
import { getStore, getVal } from './utils.js';
|
||||
const vue = {
|
||||
mixin(mixin) {
|
||||
let app = App,
|
||||
page = Page,
|
||||
component = Component;
|
||||
// 通过重写构造器实现mixin的生命周期部分
|
||||
App = (options) => {
|
||||
this.mergeHook(mixin, options);
|
||||
app(options);
|
||||
};
|
||||
Page = (options) => {
|
||||
this.mergeHook(mixin, options);
|
||||
page(options);
|
||||
};
|
||||
Component = (options) => {
|
||||
this.mergeComponentHook(mixin, options);
|
||||
const newOptions = this.mixinLifetimes(mixin, options);
|
||||
component(newOptions);
|
||||
};
|
||||
},
|
||||
// mixin实现
|
||||
mergeHook(mixin, options) {
|
||||
for (let [key, value] of Object.entries(mixin)) {
|
||||
const originFunc = options[key];
|
||||
options[key] = function (...args) {
|
||||
originFunc && originFunc.call(this, ...args);
|
||||
value.call(this, ...args);
|
||||
};
|
||||
}
|
||||
},
|
||||
//由于小程序组件钩子的特殊性,this上没有挂钩子引用,所以需要特殊处理
|
||||
mergeComponentHook(mixin, options) {
|
||||
const hooksObjectKeys = ['lifetimes', 'pageLifetimes'];
|
||||
for (let [key, value] of Object.entries(mixin).filter((e) => !hooksObjectKeys.includes(e[0]))) {
|
||||
const originFunc = options[key];
|
||||
options[key] = function (...args) {
|
||||
originFunc && originFunc.call(this, ...args);
|
||||
value.call(this, options, ...args);
|
||||
};
|
||||
}
|
||||
},
|
||||
// 使用小程序自带api混入pageLifetimes和lifetimes
|
||||
mixinLifetimes(mixin, options) {
|
||||
if (typeof Behavior === 'function') {
|
||||
const orightMixin = options.behaviors || [];
|
||||
// 由于lifetimes内的created优先级最高,则在这里做组件的初始化,传入构造参数,用来替代组件的pageHooks对象
|
||||
const originFunc = mixin.lifetimes.created;
|
||||
mixin.lifetimes.created = function (...args) {
|
||||
originFunc && originFunc.call(this, options, ...args);
|
||||
};
|
||||
orightMixin.push(
|
||||
Behavior({
|
||||
lifetimes: mixin.lifetimes,
|
||||
pageLifetimes: mixin.pageLifetimes,
|
||||
})
|
||||
);
|
||||
options.behaviors = orightMixin;
|
||||
return options;
|
||||
} else {
|
||||
const orightMixin = options.mixins || [];
|
||||
if (options.options && options.options.lifetimes) {
|
||||
const originFunc = mixin.lifetimes.created;
|
||||
mixin.lifetimes.created = function (...args) {
|
||||
originFunc && originFunc.call(this, options, ...args);
|
||||
};
|
||||
}
|
||||
orightMixin.push(
|
||||
Mixin({
|
||||
lifetimes: mixin.lifetimes,
|
||||
pageLifetimes: mixin.pageLifetimes,
|
||||
options: {
|
||||
// 允许基础库识别 lifetimes 字段以支持 lifetimes 功能
|
||||
lifetimes: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
options.mixins = orightMixin;
|
||||
return options;
|
||||
}
|
||||
},
|
||||
userAgentKey: 'miniprogram',
|
||||
};
|
||||
const subscribers = {};
|
||||
const store = {
|
||||
// 基于es5实现,不支持监听没有定义的属性
|
||||
watch(keyFun, cb, options) {
|
||||
// 获取数据仓库,一般为globalData对象
|
||||
const baseState = getStore().state;
|
||||
// 具体要监听的属性
|
||||
const watchKey = options.watchKey;
|
||||
const base = getVal(baseState, watchKey, true);
|
||||
let subscriber = {
|
||||
callback: cb,
|
||||
// 是否是卸载监听
|
||||
unwatch: false,
|
||||
};
|
||||
if (subscribers[watchKey]) {
|
||||
subscribers[watchKey].push(subscriber);
|
||||
} else {
|
||||
subscribers[watchKey] = [subscriber];
|
||||
}
|
||||
const unMonitorArrayFn = [];
|
||||
deep(base.obj, base.key);
|
||||
function deep(obj, key) {
|
||||
// 监听基本数据类型
|
||||
let name = obj[key];
|
||||
Object.defineProperty(obj, key, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
set: function (v) {
|
||||
name = v;
|
||||
subscribers[watchKey].map((subscriber) => subscriber.callback(base.obj[base.key]));
|
||||
},
|
||||
get: function () {
|
||||
return name;
|
||||
},
|
||||
});
|
||||
// 额外添加对数组长度的监听
|
||||
if (Array.isArray(obj[key])) {
|
||||
// 监听数组长度
|
||||
unMonitorArrayFn.push(
|
||||
monitorArray(obj[key], () => {
|
||||
cb(base.obj[base.key]);
|
||||
})
|
||||
);
|
||||
}
|
||||
// 递归监听引用数据类型
|
||||
if (typeof obj[key] === 'object' && obj[key] != null) {
|
||||
for (let [key_, value_] of Object.entries(obj[key])) {
|
||||
deep(obj[key], key_);
|
||||
}
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
// 取消基本数据类型监听
|
||||
subscriber.unwatch = true;
|
||||
const unwatchIndex = subscribers[watchKey].findIndex((e) => e.unwatch);
|
||||
subscribers[watchKey].splice(unwatchIndex, 1);
|
||||
if (!subscribers[watchKey].length) {
|
||||
delete subscribers[watchKey];
|
||||
}
|
||||
// 取消数组长度监听
|
||||
unMonitorArrayFn.map((f) => f());
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// 监听数组长度
|
||||
function monitorArray(array, callback) {
|
||||
// 获取Array原型
|
||||
const arrayMethods = Object.create(array);
|
||||
const unwatchFn = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].map((method) => {
|
||||
// 原生Array的原型方法
|
||||
let original = arrayMethods[method];
|
||||
define(array, method, function () {
|
||||
original.apply(this, arguments);
|
||||
// 调用对应的原生方法并返回结果(新数组长度)
|
||||
return callback.apply(this, arguments);
|
||||
});
|
||||
return () => {
|
||||
define(array, method, original);
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
unwatchFn.map((f) => f());
|
||||
};
|
||||
}
|
||||
|
||||
// 定义不可枚举的属性
|
||||
function define(obj, key, val, enumerable) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: val,
|
||||
enumerable: !!enumerable,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
export { vue, store };
|
||||
64
node_modules/spa-custom-hooks/lib/spa-custom-hooks/utils.js
generated
vendored
Normal file
64
node_modules/spa-custom-hooks/lib/spa-custom-hooks/utils.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
let store;
|
||||
/**
|
||||
* 根据动态字符串key获取属性,相当于eval
|
||||
* @param1 <object> 在此对象上查找
|
||||
* @param2 <string> | Array<string> 要找的对象key,支持字符串调用链
|
||||
* @param3 <boolean> 是否保留最后一层
|
||||
* return <any> 获取到的属性
|
||||
*/
|
||||
const getVal = (obj, keys, LastFloor) => {
|
||||
try {
|
||||
if (keys) {
|
||||
let keyArr = keys;
|
||||
if (typeof keys === 'string') {
|
||||
keyArr = keys.split('.');
|
||||
}
|
||||
// 是否保留最后一层,用于做数据监听
|
||||
const length = LastFloor ? keyArr.length - 1 : keyArr.length;
|
||||
//兼容1.1.1以及之前的版本,结束
|
||||
for (let i = 0; i < length; i++) {
|
||||
obj = obj[keyArr[i]];
|
||||
}
|
||||
return LastFloor
|
||||
? {
|
||||
key: keyArr[length],
|
||||
obj,
|
||||
}
|
||||
: obj;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 暂存store对象
|
||||
* @param <object> 传入的store对象
|
||||
* return <object> 传入的store对象
|
||||
*/
|
||||
const setStore = (_store) => {
|
||||
store = _store;
|
||||
return store;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取store对象
|
||||
* @param <App> | <Page> | <Component> 组件实例
|
||||
* return <object> store对象
|
||||
*/
|
||||
const getStore = (page) => {
|
||||
//有显式传入的store
|
||||
if (store && store.state) {
|
||||
return store;
|
||||
}
|
||||
// 否则使用组件里的store
|
||||
else if (page) {
|
||||
return page.$store || {};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
export { getVal, setStore, getStore };
|
||||
Reference in New Issue
Block a user