1. 程式人生 > >小程式開發-自定義元件的擴充套件

小程式開發-自定義元件的擴充套件

一個開始

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

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

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吧~~~

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

如果要轉載,請附上原文連結哈~