例子: https://gitee.com/akff/ak-mini-program
实现效果: 无需重复定义,自动导入对应参数
image.png
核心代码
// 1. 手动混入
/**
* 例子: (需要混入的页面中)
* import initMixin from './mixin'
* import 混入js from './js代码'
* const mixin = initMixin()
* mixin.use(引用混入js文件)
* mixin.Page({
* data: {}
* onLoad: function(){
* }
* })
*/
// 2. 全局混入
/**
* 例子: (在app.js中执行, 也可导入已封装好的global-mixin.js)
* import initMixin from './mixin'
* // 混入-基础数据(可选)
* import pageData from './global/pageData'
* mixin(pageData)
* // 注意:替换掉原Page方法
* Page = mixin.Page
*/
const originApp = App
const originPage = Page
const originComponent = Component
// 混入-基础数据
import pageData from './global/pageData'
function init(...mixinFun) {
// 可以用于拓展的生命周期
const life = {
App: ['preprocess', 'onLaunch', 'onShow', 'onHide', 'onError'],
Page: ['preprocess', 'onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'],
Component: ['preprocess', 'created', 'attached', 'ready', 'moved', 'detached', 'error']
};
// 用于保存所有的拓展生命周期函数
let lifeMixin = {};
for (let key in life) {
lifeMixin[key] = lifeMixin[key] || {};
for (let lifeTime of life[key]) {
lifeMixin[key][lifeTime] = [];
}
}
// 基类对象
// 在调用App、Page、Component前会被混入到对象中
let base = {
App: {},
Page: {},
Component: {}
}
let MpExtend = function (param) {
// 允许接收数组形式的参数
if (isArray(param)) {
param.forEach(item => MpExtend(item));
return;
}
for (const constructorName in param) {
// constructorName 应当是[App, Page, Component] 中的一个
if (!life[constructorName]) {
warning(constructorName, 'not found');
continue;
}
const option = Object.assign({}, param[constructorName]);
// 如果是生命周期中的某一个,作为生命周期拓展
for (const key in option) {
if (lifeMixin[constructorName][key]) {
lifeMixin[constructorName][key].push(option[key]);
delete option[key];
}
}
// 把剩余的属性混入到基类中
mixin(base[constructorName], option);
}
}
// 重新包装的 App、Page、Component构造函数
// 虽然都是相似的代码但是这样更利于理解和修改
const _App = decorate(originApp, function (option) {
mixin(option, base.App);
for (const lifeTime of life.App) {
option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.App[lifeTime]);
}
option['preprocess'] && option['preprocess'].call(option, option);
});
const _Page = decorate(originPage, function (option) {
mixin(option, base.Page);
for (const lifeTime of life.Page) {
option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.Page[lifeTime]);
}
option['preprocess'] && option['preprocess'].call(option, option);
});
const _Component = decorate(originComponent, function (option) {
mixin(option, base.Component);
for (const lifeTime of life.Component) {
option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.Component[lifeTime]);
}
option['preprocess'] && option['preprocess'].call(option, option);
});
// 装饰函数
// 在调用原函数之前调用所有装饰器
function decorate(f, ...decorators) {
return function () {
for (const decorator of decorators) {
decorator && decorator.apply(this, arguments);
}
return f && f.apply(this, arguments);
};
}
/**
* 实现类似混入的效果
* 类似 Object.assign, 但在遇见相同属性名均是对象时会递归进行合并而非直接覆盖
* @param o
* @param mix 可以传入多个
* 注:如果存在引用循环递归会栈溢出
*/
function mixin(o, ...mixs) {
mixs.forEach(mix => {
for (const key in mix) {
// 两个属性都是对象则递归合并
if (isObject(o[key]) && isObject(mix[key])) {
mixin(o[key], mix[key]);
} else {
o[key] = o[key] || mix[key];
}
}
// 拷贝symbol类型,(可惜小程序不支持)
for (const sym of Object.getOwnPropertySymbols(mix)) {
o[sym] = o[sym] || mix[sym];
}
});
return o;
}
function isObject(o) {
return Object.prototype.toString.call(o) === "[object Object]";
}
function isArray(o) {
return Object.prototype.toString.call(o) === "[object Array]";
}
function warning(...msg) {
MpExtend.tips && console.warn('ak-mp-extend:', ...msg);
}
Object.assign(MpExtend, {
mixin,
decorate,
lifeMixin,
App: _App,
Page: _Page,
Component: _Component,
warning,
init,
tips: true
});
// 遍历混入
for(let item of mixinFun){
MpExtend(item)
}
// 混入基础方法
MpExtend(pageData)
return MpExtend
}
// let MpExtend = init()
export default init;
方式一: 混入所有界面对象
- 在app.js中执行以下代码, 也可导入已封装好的global-mixin.js
// global-mixin.js
// 核心JS
import initMixin from './mixin'
// 混入-基础数据(可选)
import pageData from './global/pageData'
mixin(pageData)
// 注意:替换掉原Page方法
Page = mixin.Page
方式二: 手动混入,在对应界面混入
import initMixin from '../../../utils/mixins/mixin'
import pageData from '../../../utils/mixins/global/pageData'
const mixin = initMixin(pageData)
mixin.Page({
/**
* 页面的初始数据
*/
data: {},
onLoad(options) {}
})
网友评论