「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
背景
业务中,我们有一些组件是全局使用的,也就是每个页面或组件都有可能引入并使用。如果我们每个页面或组件使用一次,都要往对应的页面或组件中引入一次组件,这样做的效率太低,而且会有很多的冗余代码的产生,如何使这种全局性质的组件让使用方无痕接入,只需调用对应的方法就可以。本文提供一种思路,来供大家思考。
核心思路
- 代码引入方面:其实整体思路就是把我们需要人为写代码的地方,转化为自动插入脚本,让脚本来帮我们做这些重复的工作,也就是将需要在wxml文件中引入的组件,通过脚本来插入,免去人工写入。
- 如何提供通用的api,来让用户方便使用,这里我们可以将对应的方法挂载在实例上,这里可以参考juejin.cn/post/706568… 这篇文章,将我们的Page函数进行扩展,就可以很好的解决这个问题。这样只要通用的方法扩展到这里,这样只要每个页面引入该扩展方法,则其this上就自动挂载了。
- 仅插入到page的wxml,自定义组件的wxml则忽略,避免无效的插入,因为在自定义组件内可以直接获取当前页面实例,可以直接使用。
代码实现
以一个全局的自定义toast组件为例。
编写全局组件
这里简单实现下: 最主要的就是实现一个可对外使用的方法,这里不使用传参的方式,而是使用调用实例方法的方式。
Component({
options: {
multipleSlots: true,
},
properties: {
},
data: {
},
methods: {
showToast(options) {
const {title} = options;
this.setData({
display: true,
title,
})
},
hideToast() {
this.setData({
display: false,
})
}
},
});
全局引入插件
在app.json配置文件的usingComponents项中,将组件配置进去:
{
"usingComponents": {
"l-toast": "components/toast/index"
},
}
编写组件插入插件
这里是基于webpack来做这个事情,不再完整的实现一个webpack的配置工具,简单的实现一个插件,同样的原理,也可以用其他方式来实现。 新建parseWxml.js文件,提供插件
// 获取所有的page页面路径
const path = require('path');
const projectRoot = path.join(__dirname, '../');
const appJsonPath = path.join(projectRoot, 'src/app.json');
const appJson = require(appJsonPath);
function getAllPage() {
const pages = appJson.pages || [];
const subPages = appJson.subPackages || [];
let subPagesContent = [];
if (subPages.length) {
subPages.forEach(item => {
item.pages.forEach(page => {
subPagesContent.push(page);
})
})
}
return [...pages, ...subPagesContent]
}
class ParseWxml {
constructor(options = {}) {
}
apply(compiler) {
const pages = getAllPage();
compiler.hooks.emit.tap('ParseWxml', (compilation) => {
Object.keys(compilation.assets).forEach((item) => {
if(item.includes('.wxml')) {
if(pages.find(page => item.includes(page))) {
const content = compilation.assets[item].source();
const newContent = `${content} <l-toast id="l-toast" />`;
compilation.assets[item] = {
source: () => newContent,
size: () => newContent.length
}
}
}
})
})
}
}
module.exports = ParseWxml;
代码中已对非页面级的wxml进行了过滤,防止无效插入。
扩展方法
我们基于这篇文章,进行补充:
export default function extendPage(options) {
Page({
...options,
onLoad(params) {
// 可以在此写每个页面通用的在onLoad函数中实现的功能,最后调用用户自己的生命周期函数逻辑
console.log('通用逻辑');
if (options.onLoad) {
options.onLoad.call(this, params);
}
},
toast(options) {
this.toastEle = this.selectComponent('#l-toast');
if (this.toastEle) {
this.toastEle.showToast(options);
}
},
hideToast(){
if(this.toastEle) {
this.toastEle.hideToast();
}
}
})
}
这样就可以在页面中直接调用,this.toast()方法来进行toast展示。
同理,自定义组件也可以基于这样的封装,来提供通用的方法。只是这里,我们要注意到,由于自定义组件是没有引入自定义toast组件,所以我们要获取页面实例的方法。
getCurPage() {
const pageId = this.getPageId();
const pages = getCurrentPages();
this.curPage = pages.find(item => item.getPageId() === pageId);
return this.curPage;
}
总结
很多时候,我们不要只埋头的写代码,业务代码也是有很多值得我们提高的地方,多思考怎么把代码写的好,而且效率高才是我们不断的追求,希望本篇文章对你有所启发。