首页 >> 大全

[uniapp] uview(1.x) 二次封装u

2023-09-28 大全 20 作者:考证青年

文章目录 解决办法 方案3: 改用$emit事件机制 总结再次记录

背景介绍

项目: 使用了uview框架 1.x版本

其中对于组件 u- , 想要进行二次简单封装,把一些固定样式/固定配置等预写好, 同时对默认的返回按钮做一层前置拦截,方便后续扩展.

实现的效果

封装的组件为:

	<navBar :title="pageTitle" :isBack="true" :navbarHeight.sync="navbarHeight" :customBack="abc" >navBar>

这其中, 返回的点击事件我们要自定义的话, 可以通过:属性来传递 , 如此处的 abc

而在 组件内部:

<template><u-navbar ref='navbarex' id="nmyui" class="navbar" :is-back="isBack" :custom-back="customBackBefore" :title="title" :title-bold="true" title-color="#fff":title-width="titleWidth" back-icon-color="#fff" :is-fixed="fixed" :border-bottom="border" title-size="36" :background="background" :titleStyle="titleStyle"><view v-if="$slots.left" class="left"><slot name="left">slot>view><view v-if="$slots.right" class="right"><slot name="right">slot>view>u-navbar>template>

组件内部的 props之一

			// 自定义返回逻辑customBack: {type: Function,default: null},

我们在组件内部其实就是直接摆放了一个 u-组件

而在处理对默认返回按钮的前置拦截的时候, 我们其实是给 u-的属性 :-back=""提供了一个组件内部实现的函数

这里再说一下, 是二次封装组件, 其参数有 , 外部会给他传递诸如 abc这种函数

u-nabar是uview的导航组件, 就是对它的二次封装, 它的自定义返回事件参数名 -back , 在本次封装中, 固定给他一个 的处理方法(目的是用来做前置拦截等)

问题描述

问题就出在

这里说一句, app端(是ok的, iOS没验证,大概率也是ok的)

出问题的是小程序端

先来看报错

弯路:

第一眼看到, 又想到小程序, 第一个怀疑的是 小程序的特性对的处理肯定不一样

于是 查到这一篇文章 :

为什么木有人啊??【报Bug】自定义组件模式中子组件props接收不到数组中的

别的没仔细看, 就看了个这个

好吧, 那就用时间机制, 也就是发个 emit的方式

于是代码做修改

外部使用:

:

来看看什么下场…

点了多次返回按钮, 只打印, 没有后续了, 也没报错, 也没触发

于是去查了emit的处理, 有说不能用驼峰命名的, 有说该用 this.$.abc()的

好像两条路都走不通了

好吧, 继续耐着性子排查(期间各种尝试不表.)

总之最后, 看回到

点进去发现:

这时候才开始, 把目光放到了 this 这个罪魁祸首上面

其实上面不管用 this.$props.() or this.$emit(‘’), 最大的问题就是在 this上出了问题

因为平时主要做app端开发, 小程序接触不多, 对于这句话的理解不够深刻

uni-app坑:Props传递,该方法里的this指向子组件而不是父组件

封装次数0的不能封装了吗_封装次数限制_

这句话怎么理解呢?

举个例子 - (这里写伪代码了)

父组件 - 中,我们设置一个state 叫做 :'i am '

子组件 -sub 中,我们设置一个state 叫做 :'i am sub'

// 父组件
<component-parent><component-sub :mylogger="logger"/>
component-parent>//父组件方法
logger(){console.log(this.parentTitle)console.log(this.subTitle)
}//子组件实现
<component-sub @tap="mylogger"/>

由于在小程序中, Props传递,该方法里的this指向子组件而不是父组件

所以, 其实在父组件的 函数体中, this已经指向了 子组件 -sub, 讲白了, 此时的this.就是子组件的this

所以日志会输出

undefined
i am sub

也就是说在父组件的 方法中, 能拿到 this. , 但是拿不到this., 因为this的指向以及改变了

回到u-

由于上面的特性, 我们也看到了uview对于 u-的处理, 他们为了使用者进行自定义返回的时候避免这个坑,

他们做了如下处理

goBack() {// 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑if (typeof this.customBack === 'function') {// 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文this.customBack.bind(this.$u.$parent.call(this))();} else {uni.navigateBack();}

通过bind的方法,把this的指向又交还给了父组件, 这样作为使用者,就可以肆无忌惮的通过props传递, 从而实现多种多样的自定义返回处理.

⇒ 爸爸就该有爸爸的样子.jgp

再回到我们的问题

对于瞎玩二次封装的我们来讲, 在 子组件内部,我们的:-back=""中, 的函数体内部, this到底现在指向了谁??

打印一下

作为子组件的竟然持有函数 abc? 那很显然在

methods: {// 自定义返回-前置拦截customBackBefore() {console.log("navbar-customer-back-before")// this.$props.customBack()console.log(this)}}

此刻的子组件中的 函数体中, this指向的是父组件的

(当然,在子组件的 的生命周期等其他函数中, this还是指向子组件本身的)

为啥中this指向的是父组件

我的理解:

1.在未做二次封装之前, 我们一般直接使用 uview的u-, 一旦自定义导航事件函数, uview会帮我们处理, 把 Props传递,该方法里的this指向子组件而不是父组件 这个问题内部处理, 使得我们任何的自定义导航事件函数:-back="xxxx",在xxx中都能正确的拿回父组件的this

2.在做二次封装的时候, 最终的u-拿到的是page组件的this. 在重新bind的时候, 被组件内部的:-back拦截了

解决办法

这里有好几个方法,不过其中有坑, 我们来分析一下, 选那些合适~~~

先看看组件的,这里会添加事件的触发

	// 自定义返回-前置拦截customBackBefore() {console.log("navbar-customer-back-before")}}

再看看page 父组件中的abc函数体, 这里通过两个this,来打印确定this的指向.

		methods: {abc() {// page页的stateconsole.log(this.pageTitle)// navbar子组件的decconsole.log(this.dec)uni.showToast({title: "1abc2"})},}

方案1: 将错就错? 直接调用abc

			// 自定义返回-前置拦截customBackBefore() {console.log("navbar-customer-back-before")// 既然this已经明确指向page父组件, 那显然直接调用this.abc()是可以生效的this.abc()}}

看看日志

该方案直接就躺平了, 就直接拿父组件的函数abc来执行, 日志输出方面也表明了, 在abc函数内部的this指向是page的,大问题没有.缺点是导致组件无法通用化, 和封装的目的相违背 pass

方案2: 坚持props传

坚持props传 - 子组件中,修正this指向 自己

既然 问题出在this的指向不对,那我们做一下this的指向重置即可

子组件全局设置一个 that 用来缓存 的this

在周期函数里赋值,(因为此时的子组件在这个生命周期里,this是指向自身的)

然后再 函数体重使用即可

不过,这里插一句, 还记得那句话么

封装次数0的不能封装了吗__封装次数限制

uni-app坑:Props传递,该方法里的this指向子组件而不是父组件

对于page父组件而言, 我们封装的 同样会面临abc函数体中,this指向子组件()的问题

所以,我们来一各个测试看看this的指向

2.1

that.$props.()的写法

打印结果

结果显示: this的指向既不指向page父组件, 也不指向子组件… pass

2.2

直接的 that.()的写法

打印结果

结果显示: 调用是成功, 但是 this的指向出现了问题, page父组件的abc函数体中,this指向了子组件

2.3 bind方案

针对2.2的改进, 用 bind的方案来解决this的指向问题

打印结果

结果符合预期, this的指向也正确了

方案3: 改用$emit事件机制

当然, paga父组件里也要做一下改造,

打印结果

结果也非常符合预期, this的指向也是正确的指向了父组件~~

总结

一圈搞下来, 我们有了两种解决办法

方案2.3 和 方案3

至此,对于uview(1.x)的组件 u-的二次封装中遇到的自定义事件的处理, 也算完成.

至于选择 上面哪两种方案?

我从封装的角度出发, 我会采用方案2.3

毕竟, 二次封装也是为了后续使用方便, 还是延用 u-的自定义风格,比较合适点~

能看到这的, 都是不嫌弃我文笔凌乱的, 总之~ 谢谢观看, 如果有帮助或启发, 那就是本篇的荣幸~

再次记录

以上两个方法, 都是基于 在 vue组件 的生命周期里, 让全局变量 that = this

这里面存在一个重大的问题

that永远是只能赋值一次, 且 会被下个组件的创建加载过程, 触发 that指向的覆盖…

这就造成了bug

如: A->B->C

A默认返回 that= A.this

B默认返回 that= B.this

C自定义返回 that=C.this

一圈路由跳转下拉, that最终指向了 C ,

当C返回到B的时候, B的的that 依然是C的this…

就算及时清理that, 也会存在that 无法在B的时候 重新被 that= B.this

(其实也不是没有, 可以利用B的来重新挂载, 但是这样就显得非常麻烦…)

所以… 放弃拦截方案了,

直接把自定义事件透传给 u- 组件, 等后续我有解决办法了再行尝试

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了