小程序開發-自定義組件的擴展

一個開始

由於本人喜歡封裝組件做到高內聚,這樣的好處是,拿來就用,如果封裝一個組件,需要外部耦合,那麼將沒法做到很好的複用,因爲耦合的部分需要每次重新開發。

最近遇到了一個業務場景是這樣,如圖:

1. 頁面展示主頁,主頁可以瀏覽,也可以點擊去其他頁面,主頁有登錄按鈕,登錄按鈕點擊顯示登錄view(注意:登錄不是跳去登錄頁,而是在當前頁做view切換)。

2. 登錄view中可以填寫用戶名、密碼,可以登錄、可以返回(返回到主頁view)。

愉快的開發起開

1. 首先將主頁是小程序的一個頁面,由於我希望登錄模塊是通用的,既然不是新的頁面,就做成一個組件。

2. 登錄組件命名爲login-view,愉快的開發完畢。

3. 接下來頁面引用組件,並在wxml中使用

<view class="home-container" wx:if="{{!showLogin}}"></view>

<login-view wx:else></login-view>

4. 就這樣,定義data:showLogin, 用其控制是否切換到登錄view。

5. 當主頁中點擊登錄時,將showLogin = true。

6. 很棒,展示了登錄界面。填寫用戶名、密碼、點擊登錄,成功!。

7. 很開心,第一次測試成功了,接着第二次測試。

8. 這是第二次測試,點擊登錄,到登錄界面,輸入用戶名,這時候點擊了返回。

9. 再次點擊登錄來到了登錄界面,發現剛剛輸入的用戶名不見了

10. 留下了沒有技術的淚水,emmm...

尋找失蹤的用戶名

接下來展示思考,終於想到了爲什麼:

wx:if是dom的移除與添加,並不是顯示與隱藏,因此,在切換showLogin = false時,login-view組件被移除了,當再次點擊登錄,showLogin = true時,login-view組件又重新掛在。

好,失蹤的用戶名找到了,是wx:if將它奪走了。那麼該怎麼解決?

兩個過程

我解決此問題用了兩個過程,分別是:完成與完善。

過程一(完成):如何解決組件data丟失問題

分析:信息丟失是因爲組件的註銷與重新掛載,這是不可避免的,組件註銷後,內容永遠也保存不了。要解決的就是把組件內容保存起來

解決辦法: 信息存儲在page中,因爲page是一直生存的,組件是會註銷的。因此page中的data是不會隨着組件註銷而消失的。那麼如何將信息存放在page中?

如下:

1. 將userName和password直接放在page的data中,並且接收input事件去改變值

<login-view userName="{{userName}}" password="{{password}}" bindinput="onInput"></login-view>

2. 在page中聲明onInput,當組件中觸發此函數,則改變userName和password的值

Page({
    data: {
        userName: '',
        password: '',
    },
    // 組件中觸發事件,修改輸入框的值
    onInput(e) {
        const {key, value} = e.detail;
        this.setData({
            [key]: value,
        });
    },
});

3. 在login-view組件中,接收userName和password值,並渲染到login-view.wxml中去,這裏就不再貼代碼了。

思考:這樣修改有什麼問題?我認爲這樣的組件不能稱之爲一個優秀的組件,爲什麼?

答:我希望我的組件是拿來就用的,那麼這樣修改,我怎麼做到拿來就用?這樣的組件已與page高耦合,沒有page中的邏輯,此組件無法運行,因此我不能這樣該。

該怎樣:那麼我該怎樣該達到我緩存數據的目的呢?

過程二(完善):開發低耦合高內聚的靈活性組件

首先看完善後的業務上該怎麼用

<login-view></login-view>

wxml裏直接這樣使用,那麼page的js裏呢?答案:不需要任何代碼。這麼神奇麼?就是這麼神奇。

思路: 保存原來代碼不變,login-view做了任何login-view該做的事情,數據存儲、數據更新都在組件內完成。我要做的是做到組件重新掛在,數據緩存。該怎樣做?

同樣,利用page data緩存數據,但是不需要主動去定義,在login-view組件裏做手腳:

const Base = require('./wx-component.js');
Component(Base({
    name: 'login',
    $$data: {
        userName: '',
        password: '',
    },
    methods: {
        onInput(e) {
            const key = e.currentTarget.dataset.key;
            const value = e.detail.value;
            this.setData({
                [key]: value,
            });
        },
    },
}));

以上代碼,引用了wx-component.js,暴露一個方法,將原本傳遞給Component的options對象傳遞給他,Base(options),然後再將其返回值傳遞給Component,Component(Base(options))。做了一層包裝。就這樣,就完成了數據緩存,再次切換login-view時,數據依舊保存着。

那麼看到這裏讀者要問:wx-component是什麼鬼?$$data又是什麼?

三個BUFF

wx-component.js是自己封裝的一個組件增強的擴展函數,他可以輕鬆賦予你三個特殊能力。

1. 逆向數據綁定

什麼意思?我們都知道,page中的data可以傳遞給組件使用,並且page中data更新,組件中的view頁同步更新,但是組件中的data更新不會反射到page中。

那麼這第一個buff就是:組件data更新引發page中data的更新,換句話說,page的data中會時時存儲組件data的一個副本。因此我叫他逆向數據綁定。

代碼如下:

const Base = require('./wx-component.js');
Component(Base({
    // 聲明增強組件的name
    name: 'login',
    // 聲明逆向數據綁定的data
    $$data: {
        userName: '',
        password: '',
    },
}));

name是必須聲明的,使用增強組件功能,需要聲明唯一name值,比如‘login’,$$data屬性是逆向數據綁定的所有數據,其他不需要逆向數據綁定的數據依舊放在data中。

這樣就完成了component.$$data -> page.data的功能,在組件setData改變userName和password的值會同步到page.data中去。

那你怎麼可以在page中獲取到他呢?在page中用this.data.$[name]格式,此例子中爲:this.data.$login就獲取到了逆向數據的對象。

2. 組件數據緩存

有了逆向數據綁定,你可能猜到了,就用這種方法可以把數據存儲到page中了,那麼在組件註銷後重新掛載,我們可以拿到此份數據來進行渲染到組件。

這部分代碼在wx-component.js中做體現,業務中並不需要做額外的事情。

3. 方法暴露

很多時候,組件內部的一些方法,page中其實也需要用到的, 比如:tab組件,點擊某個tab,則變爲激活狀態,在page中可能也是需要主動去改變某個tab的激活狀態,因此需要用到組件內部方法。

當然組件內部方法是有辦法獲取的,官方文檔有介紹如何獲取組件實例,獲取到組件實例,當然就可以使用其方法,但這樣很麻煩的,我可以提供更好的方法。

const Base = require('./wx-component.js');
Component(Base({
    name: 'login',
    $$data: {
        userName: '',
        password: '',
    },
    // 定義向page暴露的方法
    $parentMethods: {
        reset() {
            this.setData({
                userName: '',
                password: '',
            });
        },
    },
}));

如上用$parentMethods對象來暴露給page方法,在page中可以直接調用

Page({
  onReset() {
    // $login來獲取暴露的方法
    this.$login.reset();
  }
})

最後的最後

這就是wx-component的功能,功能並不是通用的,只適合部分業務場景。如果你的業務放好需要這樣做,你就可以用到它。

github點這裏

如果對你有幫助,點一個star吧~~~

如果有錯誤的地方,請提issue吧~~~

如果有什麼建議的,歡迎留言哈~~~

如果要轉載,請附上原文鏈接哈~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章