• 小程序开发-自定义组件的扩展


    一个开始

    由于本人喜欢封装组件做到高内聚,这样的好处是,拿来就用,如果封装一个组件,需要外部耦合,那么将没法做到很好的复用,因为耦合的部分需要每次重新开发。

    最近遇到了一个业务场景是这样,如图:

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

    如果有什么建议的,欢迎留言哈~~~

    如果要转载,请附上原文链接哈~~~

  • 相关阅读:
    Hybrid APP基础篇(四)->JSBridge的原理
    剑指offer
    剑指offer
    如何在HTML中设置文本的大小写
    如何给HTML标签中的文本设置修饰线
    CSS设置文本的水平对齐方向
    如何在HTML中设置字体颜色,你知道这几种方式吗?
    CSS尺寸样式属性
    CSS基本选择器是什么?基本选择器是如何工作
    如何创建 CSS
  • 原文地址:https://www.cnblogs.com/xujiazheng/p/11558361.html
Copyright © 2020-2023  润新知