2020-04-05

微信小程序-气泡框

写在前面


问题截图

popover问题截图

问题描述

  • 模拟器显示正常,但在真机上点击后,气泡框的箭头并没有消失,且点击同一级别区域,能利用覆盖消除箭头。【是不是一个很可爱的bug?

问题解决过程记录

  • 定位问题发生的原因范围

    • 样式
      • 样式在判断显示条件(wx:if=”“)生效后,仍然渲染
      • 否定原因
        • 查询代码发现,整个样式背景的设定是在::before伪元素选择器中
        • 且显示条件生效,在调试器中已没有该元素,但仍显示
    • 逻辑
      • 会不会是组件在渲染时,多渲染一份,我们使用判断条件进行开关时,只是对其中一个进行了操作
      • 怀疑依据
        • popover问题依据截图
        • 上图可见:在popover组件下,有2个通过<slot>插入的相同内容
  • 开始解决问题

    • 查询官方关于slot方面的介绍
      • 官方slot基础例子
    • 基于官方基础代码,复现问题
      • 产生一个child-tag组件,并在其中编写
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        // components/child-tag.js.js
        Component({
        options: {
        multipleSlots: true // 在组件定义时的选项中启用多slot支持
        },
        /**
        * 组件的属性列表
        */
        properties: {

        },
        relations: {
        './component-tag-name': {
        type: 'parent',
        }
        },

        /**
        * 组件的初始数据
        */
        data: {

        },

        /**
        * 组件的方法列表
        */
        methods: {

        }
        })
      • 与component-tag-name绑定形成父子组件
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        // components/component-tag-name.js
        Component({
        options: {
        multipleSlots: true // 在组件定义时的选项中启用多slot支持
        },
        relations: {
        './child-tag': {
        type: 'child',
        }
        },
        /**
        * 组件的属性列表
        */
        properties: {
        },

        /**
        * 组件的初始数据
        */
        data: {
        visible: false
        },

        /**
        * 组件的方法列表
        */
        methods: {

        }
        })
      • 并将index.html中进行调用
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        <!-- 引用组件的页面模版 -->
        <view>
        <button type="primary" bindtap="onTap">222</button>
        <my-component id="component">
        <view slot="content">
        这里是插入到组件slot name="content"中的内容
        <child-component>
        <view slot="child">这里是插入到组件slot name="child"中的内容</view>
        </child-component>
        </view>
        </my-component>
        </view>
      • 但是其结构树仍然非常正常,并没有出现那个所谓的”拷贝”组件
        • 改写v1.1后的结构树截图
        • 仔细复现了几次,发现:多出来的那个组件会有所延迟。抓住这个问题,想到我们在onReady中,注册了该组件,于是,继续模拟
      • 修改index.js代码,并在component-tag-name组件注册onTap方法,控制显隐
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        onReady() {
        this.component = this.selectComponent('#component')
        },
        onTap() {
        console.log('onTap')
        wx.createSelectorQuery().select('#component').boundingClientRect(res => {
        // 调用自定义组件 popover 中的 onDisplay 方法
        this.component.onTap();
        }).exec();
        }
      • 最终复现
        • 官方模拟最终运行截图
    • 得出问题来源:
      • 在组件中进行了一次setData
    • 思考背后问题
      • 在组件中setData为什么会”拷贝“一份相同的在页面级wxml中?
      • 猜想一:从WXS响应事件中,我隐隐得到了答案
      • wxs相应事件
      • 我们在页面级通过selectComponent实例化组件,对选中的组件进行操作,官方可以通过拷贝一份相同的组件,使我们便捷的将事件的处理从2次的逻辑层和渲染层通信以及一次渲染,减少到直接对页面上元素进行操作,即一次逻辑层和渲染层通信以及一次渲染。
      • 猜想二:问题层面是在微信开发者工具中的wxml,渲染方式对于这种情况就是这样处理的。
  • 官方已给出问题原因

    • wxml面板

如何解决问题

  • 在popover以及popover-item加入
    1
    2
    3
    options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
    },
  • 就可以解决了。最后建议slot中可以写上name这样代码可能会更易读。

    写在后面

  • 祝大家多多发财