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

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

1. 页面展示主页,主页可以浏览,也可以点击去其他页面,主页有登录按钮,登录按钮点击显示登录view(注意:登录不是跳去登录页,而是在当前页做view切换)。

2. 登录view中可以填写用户名、密码,可以登录、可以返回(返回到主页view)。

1. 首先将主页是小程序的一个页面,由于我希望登录模块是通用的,既然不是新的页面,就做成一个组件。

2. 登录组件命名为login-view,愉快的开发完毕。

3. 接下来页面引用组件,并在wxml中使用

  1. <view class="home-container" wx:if="{{!showLogin}}"></view>
  2.  
  3. <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将它夺走了。那么该怎么解决?

我解决此问题用了两个过程,分别是:完成与完善。

分析:信息丢失是因为组件的注销与重新挂载,这是不可避免的,组件注销后,内容永远也保存不了。要解决的就是把组件内容保存起来

解决办法: 信息存储在page中,因为page是一直生存的,组件是会注销的。因此page中的data是不会随着组件注销而消失的。那么如何将信息存放在page中?

如下:

1. 将userName和password直接放在page的data中,并且接收input事件去改变值

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

2. 在page中声明onInput,当组件中触发此函数,则改变userName和password的值

  1. Page({
  2. data: {
  3. userName: \'\',
  4. password: \'\',
  5. },
  6. // 组件中触发事件,修改输入框的值
  7. onInput(e) {
  8. const {key, value} = e.detail;
  9. this.setData({
  10. [key]: value,
  11. });
  12. },
  13. });

3. 在login-view组件中,接收userName和password值,并渲染到login-view.wxml中去,这里就不再贴代码了。

思考:这样修改有什么问题?我认为这样的组件不能称之为一个优秀的组件,为什么?

答:我希望我的组件是拿来就用的,那么这样修改,我怎么做到拿来就用?这样的组件已与page高耦合,没有page中的逻辑,此组件无法运行,因此我不能这样该。

该怎样:那么我该怎样该达到我缓存数据的目的呢?

首先看完善后的业务上该怎么用

  1. <login-view></login-view>

wxml里直接这样使用,那么page的js里呢?答案:不需要任何代码。这么神奇么?就是这么神奇。

思路: 保存原来代码不变,login-view做了任何login-view该做的事情,数据存储、数据更新都在组件内完成。我要做的是做到组件重新挂在,数据缓存。该怎样做?

同样,利用page data缓存数据,但是不需要主动去定义,在login-view组件里做手脚:

  1. const Base = require(\'./wx-component.js\');
  2. Component(Base({
  3. name: \'login\',
  4. $$data: {
  5. userName: \'\',
  6. password: \'\',
  7. },
  8. methods: {
  9. onInput(e) {
  10. const key = e.currentTarget.dataset.key;
  11. const value = e.detail.value;
  12. this.setData({
  13. [key]: value,
  14. });
  15. },
  16. },
  17. }));

以上代码,引用了wx-component.js,暴露一个方法,将原本传递给Component的options对象传递给他,Base(options),然后再将其返回值传递给Component,Component(Base(options))。做了一层包装。就这样,就完成了数据缓存,再次切换login-view时,数据依旧保存着。

那么看到这里读者要问:wx-component是什么鬼?$$data又是什么?

wx-component.js是自己封装的一个组件增强的扩展函数,他可以轻松赋予你三个特殊能力。

什么意思?我们都知道,page中的data可以传递给组件使用,并且page中data更新,组件中的view页同步更新,但是组件中的data更新不会反射到page中。

那么这第一个buff就是:组件data更新引发page中data的更新,换句话说,page的data中会时时存储组件data的一个副本。因此我叫他逆向数据绑定。

代码如下:

  1. const Base = require(\'./wx-component.js\');
  2. Component(Base({
  3. // 声明增强组件的name
  4. name: \'login\',
  5. // 声明逆向数据绑定的data
  6. $$data: {
  7. userName: \'\',
  8. password: \'\',
  9. },
  10. }));

name是必须声明的,使用增强组件功能,需要声明唯一name值,比如‘login’,$$data属性是逆向数据绑定的所有数据,其他不需要逆向数据绑定的数据依旧放在data中。

这样就完成了component.$$data -> page.data的功能,在组件setData改变userName和password的值会同步到page.data中去。

那你怎么可以在page中获取到他呢?在page中用this.data.$[name]格式,此例子中为:this.data.$login就获取到了逆向数据的对象。

有了逆向数据绑定,你可能猜到了,就用这种方法可以把数据存储到page中了,那么在组件注销后重新挂载,我们可以拿到此份数据来进行渲染到组件。

这部分代码在wx-component.js中做体现,业务中并不需要做额外的事情。

很多时候,组件内部的一些方法,page中其实也需要用到的, 比如:tab组件,点击某个tab,则变为激活状态,在page中可能也是需要主动去改变某个tab的激活状态,因此需要用到组件内部方法。

当然组件内部方法是有办法获取的,官方文档有介绍如何获取组件实例,获取到组件实例,当然就可以使用其方法,但这样很麻烦的,我可以提供更好的方法。

  1. const Base = require(\'./wx-component.js\');
  2. Component(Base({
  3. name: \'login\',
  4. $$data: {
  5. userName: \'\',
  6. password: \'\',
  7. },
  8. // 定义向page暴露的方法
  9. $parentMethods: {
  10. reset() {
  11. this.setData({
  12. userName: \'\',
  13. password: \'\',
  14. });
  15. },
  16. },
  17. }));

如上用$parentMethods对象来暴露给page方法,在page中可以直接调用

  1. Page({
  2. onReset() {
  3. // $login来获取暴露的方法
  4. this.$login.reset();
  5. }
  6. })

这就是wx-component的功能,功能并不是通用的,只适合部分业务场景。如果你的业务放好需要这样做,你就可以用到它。

github点这里

如果对你有帮助,点一个star吧~~~

如果有错误的地方,请提issue吧~~~

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

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

版权声明:本文为xujiazheng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xujiazheng/p/11558361.html