南宫云遥 發表於 2019-9-20 17:12:00

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

<h2>一个开始</h2>
<p>由于本人喜欢封装组件做到高内聚,这样的好处是,拿来就用,如果封装一个组件,需要外部耦合,那么将没法做到很好的复用,因为耦合的部分需要每次重新开发。</p>
<p>最近遇到了一个业务场景是这样,如图:</p>
<p><img src="http://qn.zhangyy.xyz/a615732014.png"></p>
<p>1. 页面展示主页,主页可以浏览,也可以点击去其他页面,主页有登录按钮,登录按钮点击显示登录view(注意:登录不是跳去登录页,而是在当前页做view切换)。</p>
<p>2. 登录view中可以填写用户名、密码,可以登录、可以返回(返回到主页view)。</p>
<h3>愉快的开发起开</h3>
<p>1. 首先将主页是小程序的一个页面,由于我希望登录模块是通用的,既然不是新的页面,就做成一个组件。</p>
<p>2. 登录组件命名为login-view,愉快的开发完毕。</p>
<p>3. 接下来页面引用组件,并在wxml中使用</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="home-container"</span><span style="color: rgba(255, 0, 0, 1)"> wx:if</span><span style="color: rgba(0, 0, 255, 1)">="{{!showLogin}}"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">login-view </span><span style="color: rgba(255, 0, 0, 1)">wx:else</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">login-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>4. 就这样,定义data:showLogin, 用其控制是否切换到登录view。</p>
<p>5. 当主页中点击登录时,将showLogin = true。</p>
<p>6. 很棒,展示了登录界面。填写用户名、密码、点击登录,成功!。</p>
<p>7. 很开心,第一次测试成功了,接着第二次测试。</p>
<p>8. 这是第二次测试,点击登录,到登录界面,输入用户名,这时候点击了返回。</p>
<p>9. 再次点击登录来到了登录界面,<strong>发现刚刚输入的用户名不见了</strong></p>
<p>10. 留下了没有技术的泪水,emmm...</p>
<h3>寻找失踪的用户名</h3>
<p>接下来展示思考,终于想到了为什么:</p>
<p>wx:if是dom的移除与添加,并不是显示与隐藏,因此,在切换showLogin = false时,login-view组件被移除了,当再次点击登录,showLogin = true时,login-view组件又重新挂在。</p>
<p>好,失踪的用户名找到了,是wx:if将它夺走了。那么该怎么解决?</p>
<h2>两个过程</h2>
<p>我解决此问题用了两个过程,分别是:完成与完善。</p>
<h3>过程一(完成):如何解决组件data丢失问题</h3>
<p>分析:信息丢失是因为组件的注销与重新挂载,这是不可避免的,组件注销后,内容永远也保存不了。要解决的就是把组件内容保存起来</p>
<p>解决办法: 信息存储在page中,因为page是一直生存的,组件是会注销的。因此page中的data是不会随着组件注销而消失的。那么如何将信息存放在page中?</p>
<p>如下:</p>
<p>1. 将userName和password直接放在page的data中,并且接收input事件去改变值</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">login-view </span><span style="color: rgba(255, 0, 0, 1)">userName</span><span style="color: rgba(0, 0, 255, 1)">="{{userName}}"</span><span style="color: rgba(255, 0, 0, 1)"> password</span><span style="color: rgba(0, 0, 255, 1)">="{{password}}"</span><span style="color: rgba(255, 0, 0, 1)"> bindinput</span><span style="color: rgba(0, 0, 255, 1)">="onInput"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">login-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>2. 在page中声明onInput,当组件中触发此函数,则改变userName和password的值</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Page({
    data: {
      userName: </span>''<span style="color: rgba(0, 0, 0, 1)">,
      password: </span>''<span style="color: rgba(0, 0, 0, 1)">,
    },
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 组件中触发事件,修改输入框的值</span>
<span style="color: rgba(0, 0, 0, 1)">    onInput(e) {
      const {key, value} </span>=<span style="color: rgba(0, 0, 0, 1)"> e.detail;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setData({
            : value,
      });
    },
});</span></pre>
</div>
<p>3. 在login-view组件中,接收userName和password值,并渲染到login-view.wxml中去,这里就不再贴代码了。</p>
<p><strong>思考:这样修改有什么问题?我认为这样的组件不能称之为一个优秀的组件,为什么?</strong></p>
<p><strong>答:我希望我的组件是拿来就用的,那么这样修改,我怎么做到拿来就用?这样的组件已与page高耦合,没有page中的逻辑,此组件无法运行,因此我不能这样该。</strong></p>
<p><strong>该怎样:那么我该怎样该达到我缓存数据的目的呢?</strong></p>
<h3>过程二(完善):开发低耦合高内聚的灵活性组件</h3>
<p>首先看完善后的业务上该怎么用</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">login-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">login-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>wxml里直接这样使用,那么page的js里呢?答案:不需要任何代码。这么神奇么?就是这么神奇。</p>
<p>思路: 保存原来代码不变,login-view做了任何login-view该做的事情,数据存储、数据更新都在组件内完成。我要做的是做到组件重新挂在,数据缓存。该怎样做?</p>
<p>同样,利用page data缓存数据,但是不需要主动去定义,在login-view组件里做手脚:</p>
<div class="cnblogs_code">
<pre>const Base = require('./wx-component.js'<span style="color: rgba(0, 0, 0, 1)">);
Component(Base({
    name: </span>'login'<span style="color: rgba(0, 0, 0, 1)">,
    $$data: {
      userName: </span>''<span style="color: rgba(0, 0, 0, 1)">,
      password: </span>''<span style="color: rgba(0, 0, 0, 1)">,
    },
    methods: {
      onInput(e) {
            const key </span>=<span style="color: rgba(0, 0, 0, 1)"> e.currentTarget.dataset.key;
            const value </span>=<span style="color: rgba(0, 0, 0, 1)"> e.detail.value;
            </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setData({
                : value,
            });
      },
    },
}));</span></pre>
</div>
<p>以上代码,引用了wx-component.js,暴露一个方法,将原本传递给Component的options对象传递给他,Base(options),然后再将其返回值传递给Component,Component(Base(options))。做了一层包装。就这样,就完成了数据缓存,再次切换login-view时,数据依旧保存着。</p>
<p>那么看到这里读者要问:<strong>wx-component是什么鬼?$$data又是什么?</strong></p>
<h2>三个BUFF</h2>
<p>wx-component.js是自己封装的一个组件增强的扩展函数,他可以轻松赋予你三个特殊能力。</p>
<h3>1. 逆向数据绑定</h3>
<p>什么意思?我们都知道,page中的data可以传递给组件使用,并且page中data更新,组件中的view页同步更新,但是组件中的data更新不会反射到page中。</p>
<p>那么这第一个buff就是:组件data更新引发page中data的更新,换句话说,page的data中会时时存储组件data的一个副本。因此我叫他逆向数据绑定。</p>
<p>代码如下:</p>
<div class="cnblogs_code">
<pre>const Base = require('./wx-component.js'<span style="color: rgba(0, 0, 0, 1)">);
Component(Base({
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 声明增强组件的name</span>
    name: 'login'<span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 声明逆向数据绑定的data</span>
<span style="color: rgba(0, 0, 0, 1)">    $$data: {
      userName: </span>''<span style="color: rgba(0, 0, 0, 1)">,
      password: </span>''<span style="color: rgba(0, 0, 0, 1)">,
    },
}));</span></pre>
</div>
<p>name是必须声明的,使用增强组件功能,需要声明唯一name值,比如‘login’,$$data属性是逆向数据绑定的所有数据,其他不需要逆向数据绑定的数据依旧放在data中。</p>
<p>这样就完成了component.$$data -&gt; page.data的功能,在组件setData改变userName和password的值会同步到page.data中去。</p>
<p>那你怎么可以在page中获取到他呢?在page中用this.data.$格式,此例子中为:this.data.$login就获取到了逆向数据的对象。</p>
<h3>2. 组件数据缓存</h3>
<p>有了逆向数据绑定,你可能猜到了,就用这种方法可以把数据存储到page中了,那么在组件注销后重新挂载,我们可以拿到此份数据来进行渲染到组件。</p>
<p>这部分代码在wx-component.js中做体现,业务中并不需要做额外的事情。</p>
<h3>3. 方法暴露</h3>
<p>很多时候,组件内部的一些方法,page中其实也需要用到的, 比如:tab组件,点击某个tab,则变为激活状态,在page中可能也是需要主动去改变某个tab的激活状态,因此需要用到组件内部方法。</p>
<p>当然组件内部方法是有办法获取的,官方文档有介绍如何获取组件实例,获取到组件实例,当然就可以使用其方法,但这样很麻烦的,我可以提供更好的方法。</p>
<div class="cnblogs_code">
<pre>const Base = require('./wx-component.js'<span style="color: rgba(0, 0, 0, 1)">);
Component(Base({
    name: </span>'login'<span style="color: rgba(0, 0, 0, 1)">,
    $$data: {
      userName: </span>''<span style="color: rgba(0, 0, 0, 1)">,
      password: </span>''<span style="color: rgba(0, 0, 0, 1)">,
    },
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义向page暴露的方法</span>
<span style="color: rgba(0, 0, 0, 1)">    $parentMethods: {
      reset() {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setData({
                userName: </span>''<span style="color: rgba(0, 0, 0, 1)">,
                password: </span>''<span style="color: rgba(0, 0, 0, 1)">,
            });
      },
    },
}));</span></pre>
</div>
<p>如上用$parentMethods对象来暴露给page方法,在page中可以直接调用</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Page({
onReset() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> $login来获取暴露的方法</span>
    <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$login.reset();
}
})</span></pre>
</div>
<h2>最后的最后</h2>
<p>这就是wx-component的功能,功能并不是通用的,只适合部分业务场景。如果你的业务放好需要这样做,你就可以用到它。</p>
<p>github点这里</p>
<p>如果对你有帮助,点一个star吧~~~</p>
<p>如果有错误的地方,请提issue吧~~~</p>
<p>如果有什么建议的,欢迎留言哈~~~</p>
<p>如果要转载,请附上原文链接哈~~~</p><br><br>
来源:https://www.cnblogs.com/xujiazheng/p/11558361.html
頁: [1]
查看完整版本: 小程序开发-自定义组件的扩展