為您解碼網(wǎng)站建設(shè)的點(diǎn)點(diǎn)滴滴
發(fā)表日期:2019-11 文章編輯:小燈 瀏覽次數(shù):4868
戰(zhàn)爭(zhēng),信念,意志和情感,這些散發(fā)著光芒和硝煙的詞匯,象一枚枚炮彈轟入我們現(xiàn)在的生活。歷史的記憶不會(huì)被抹滅。
當(dāng)我們?cè)诟髯皂?xiàng)目里幸福的拷貝著官方代碼 demo,在 componnets
文件夾里使用 Component
方法書(shū)寫(xiě)一個(gè)個(gè)組件時(shí),不要忘記,在 2018 年上半年以前,小程序是沒(méi)有提供組件化方案的。
當(dāng)時(shí),主要有兩種解決方法,一種是 WePY 拷貝法,另一種則是摩拜 template 法。
比如有個(gè)最簡(jiǎn)單的按鈕組件:
<!-- components/button.wpy -->
<template>
<view class="button">
<button @tap="onTap">點(diǎn)這里</button>
</view>
</template>
<!-- pages/index.wpy -->
<template>
<view class="container">
<wpy-button /> // button 組件1
<wpy-button2 /> // button 組件2
</view>
</template>
經(jīng)過(guò)編譯后結(jié)果如下:
<view class="container">
<view class="button">
<button bindtap="$wpyButton$onTap">點(diǎn)這里</button>
</view>
<view class="button">
<button bindtap="$wpyButton2$onTap">點(diǎn)這里</button>
</view>
</view>
為了方便變量隔離,所以引入到頁(yè)面中的組件得單獨(dú)命名:
import wepy from 'wepy'
import Button from '@/components/button'
export default class Index extends wepy.page {
components = {
'wpy-button': Button,
'wpy-button2': Button
}
...
}
有一些不便的地方,但也很好的解決了組件化缺失的問(wèn)題。
有心的同學(xué)可能記得當(dāng)初我們發(fā)了這篇文章:微信小程序組件化解決方案wx-component,當(dāng)時(shí)主要講了如何使用,這次講講技術(shù)的細(xì)節(jié)。
主要利用小程序當(dāng)時(shí)提供的 template
模板方法,使用方式如下:
<!-- pages/template/login.wxml -->
<template name="login">
<view class="login">這是登錄組件</view>
</template>
<!-- pages/login/index.wxml -->
<import src='../../components/login/index.wxml'/>
<view class="login-box">
<template is="login" data="{{...}}"></template>
</view>
由于知道這只是臨時(shí)的解決方法,最終還會(huì)遷移到微信官方組件化方案。了解到微信團(tuán)隊(duì)正在開(kāi)發(fā),就死皮賴(lài)臉找了微信研發(fā)同學(xué)要下技術(shù)方案,以便后期遷移成本做到最低。最后微信同學(xué)不耐煩的扔給我們?nèi)缦麓a,并特別囑咐不要泄露出去:
Component({
// 組件名
name: '',
// 為其他組件指定別名
using: {},
// 類(lèi)似mixins,組件間代碼復(fù)用
behaviors: [],
// 組件私有數(shù)據(jù)
data: {
},
// 外部傳入的組件屬性
propties: {
},
// 當(dāng)組件被加載
attached () {
},
// 當(dāng)組件被卸載
detached () {
},
// 組件私有方法
methods: {
}
})
一目了然,依照此文檔實(shí)現(xiàn)一個(gè)簡(jiǎn)單的組件化方案也有了思路。
由于沒(méi)有辦法在小程序全局注入 Component
方法,可以將組件代碼以模塊方式導(dǎo)出,在頁(yè)面的 Page
方法里引入:
// components/login/index.wxml
<template name="login">
<form bindsubmit="onLoginSubmit">
...
<button type="primary" formType="submit">{{btnText}}</button>
</form>
</template>
// components/login/index.js
module.exports = {
name: 'login',
data: {
btnText: ''
}
....
}
// pages/index/index.js
Page({
data: {
...
},
components: {
login: {
btnText: '開(kāi)始',
onLoginCallback() { ... }
}
}
})
<!-- pages/index/index.wxml -->
<import src='../../components/login/index.wxml'/>
<view class="login-box">
<template is="login" data="{{...login}}"></template>
</view>
在 Page
的傳參里多了 components
屬性,傳入了組件名login
,以及組件對(duì)應(yīng)的屬性值和方法。為了使這些新增傳參生效,那勢(shì)必需要對(duì) Page
進(jìn)行改造。
如何用一行代碼毀掉你的小程序,在小程序根目錄的 app.js
里加入這段代碼即可:
Page = funtion() {}
這樣核心的 Page
的方法就被覆蓋掉了,所以利用這個(gè)“特性”,可以改造 Page
方法:
// utils/wx.js
var page = function() {
// 改造代碼
...
}
module.exports = {
page
}
// app.js
Page = require('./utils/wx').page
這就完成了獨(dú)一無(wú)二的自定義的小程序 Page
的方法。
精簡(jiǎn)了核心的代碼如下:
function noop() {}
class Component {
constructor (config) {
// 兼容 onLoad onUnload 的寫(xiě)法
config.onLoad = config.onLoad || config.attached || noop
config.onUnload = config.onUnload || config.detached || noop
this.data = config.data || {}
this.config = config
this.methods = config.methods || {}
for (let name in this.methods) {
// 為了使組件事件綁定生效,直接掛在到 this 下
this[name] = methods[name]
}
}
setData (data, deepExtend) {
let name = this.name
let parent = this.parent
let mergeData = extend(deepExtend !== false, parent.data[name], data)
let newData = {}
newData[name] = mergeData
this.data = mergeData
// 更新頁(yè)面的 data
parent.setData(newData)
}
setName (name) {
this.name = name
}
setParent (parent) {
this.parent = parent
}
}
主要完成了三件事:
attached
和 detached
template
的 bindtap
等代碼生效setData
功能有個(gè)細(xì)節(jié),為了讓大家容易理解(不泄露微信的方法名),分享到外部的文章用 onLoad
、onUnload
代替了 attached
、detached
,但內(nèi)部早就開(kāi)始用微信命名的這兩個(gè)屬性名,才有了代碼中的兼容寫(xiě)法。
整理了大致的核心代碼如下:
// 緩存下微信的 Page
const originalPage = Page
// 組件生命周期
const LIFETIME_EVENT = [
'onLoad',
'onUnload'
]
class MyPage {
constructor (origin) {
this.origin = origin
this.config = {}
this.children = {}
this.childrenEvents = {}
// 是否需要`components`
let components = this.components = origin.components
if (components) {
this.config.data = {}
for (let item in components) {
let props = components[item] || {}
let component = new Component(require(`../components/${item}/index`))
this.children[name] = component
// 合并組件的 data
extend(component.data, component.props)
// ...
// 合并組件的 method
for (let fnName in component.methods) {
this.config[fnName] = component.methods[fnName].bind(component)
}
// ...
let childrenEvents = this.childrenEvents[item] = {}
LIFETIME_EVENT.forEach((prop) => {
childrenEvents[item][prop] = component.config[prop]
})
}
// 合并所有依賴(lài)組件的生命周期函數(shù)
LIFETIME_EVENT.forEach((prop) => {
this.config[prop] = () => {
for (let item in this.components) {
this.childrenEvents[item][prop].apply(this.component, arguments)
}
this.origin[prop] && this.origin[prop].apply(this, arguments)
}
})
// 把新生成的 config 傳給原始的微信的 Page 方法
originalPage(this.config)
} else {
// 沒(méi)有依賴(lài)組件,直接透?jìng)鹘o微信的 Page 方法
originalPage(origin)
}
}
}
可能有點(diǎn)亂,其實(shí)就是不斷 merge data
和 method
的過(guò)程。最終所有組件自定的數(shù)據(jù)和方法都被掛在到了 Page
的傳參里。
最后,導(dǎo)出自定義的 page
:
// utils/wx.js
const page = function (config) {
return new MyPage(config)
}
module.exports = {
page
}
在 app.js
中覆蓋掉原有的 Page
方法:
// app.js
Page = require('./utils/wx').page
雖然滿(mǎn)足業(yè)務(wù)了,但也是有些問(wèn)題的,例如上面 MyPage
方法里的這段:
for (let fnName in component.methods) {
this.config[fnName] = component.methods[fnName].bind(component)
}
可以看出,直接把組件內(nèi)部定義的方法,掛在到 config
中去了,這就要求頁(yè)面的方法和組件的方法不能重名,這是為了方便 template
可以直接綁定組件定義的事件,只能通過(guò)把組件事件轉(zhuǎn)移到頁(yè)面的事件方法里。
也有很多不完善的地方,但通過(guò)內(nèi)部約束代碼規(guī)范也基本可以解決。
這種近乎 Hack 的方式支撐了摩拜單車(chē)小程序業(yè)務(wù)大半年的時(shí)間,期間產(chǎn)出了大大小小十多個(gè)組件。而由于組件內(nèi)部基本是按照微信官方組件化 api 書(shū)寫(xiě),等待官方推出組件化方案后,全部遷移過(guò)去的成本也大大減小。
日期:2019-11 瀏覽次數(shù):5528
日期:2019-11 瀏覽次數(shù):11984
日期:2019-11 瀏覽次數(shù):4353
日期:2019-11 瀏覽次數(shù):5388
日期:2019-11 瀏覽次數(shù):5261
日期:2019-11 瀏覽次數(shù):7183
日期:2019-11 瀏覽次數(shù):5166
日期:2019-11 瀏覽次數(shù):15770
日期:2019-11 瀏覽次數(shù):4721
日期:2019-11 瀏覽次數(shù):6520
日期:2019-11 瀏覽次數(shù):5374
日期:2019-11 瀏覽次數(shù):4565
日期:2019-11 瀏覽次數(shù):10764
日期:2019-11 瀏覽次數(shù):8321
日期:2019-11 瀏覽次數(shù):5081
日期:2019-11 瀏覽次數(shù):4314
日期:2019-11 瀏覽次數(shù):8955
日期:2019-11 瀏覽次數(shù):4650
日期:2019-11 瀏覽次數(shù):4847
日期:2019-11 瀏覽次數(shù):4867
日期:2019-11 瀏覽次數(shù):4480
日期:2019-11 瀏覽次數(shù):5028
日期:2019-11 瀏覽次數(shù):10284
日期:2019-11 瀏覽次數(shù):5461
日期:2019-11 瀏覽次數(shù):5438
日期:2019-11 瀏覽次數(shù):4887
日期:2019-11 瀏覽次數(shù):12333
日期:2019-11 瀏覽次數(shù):7356
日期:2019-11 瀏覽次數(shù):7905
日期:2019-11 瀏覽次數(shù):4858
Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.