1. 组件通信
1.1. 父子组件通信
- 父传子
子组件通过properties接受这个属性,这个属性会被放到子组件的data里,可以使用this.data.attrname拿到这个属性值
parent.xml
<view>
<child test="aaa"></child>
</view>
child.js
Component({
properties: {
test: {
type: String,
value: ''
}
}
})
- 子传父
子组件通过triggerEvent
触发父组件自定义事件,在使用这个组件的时候在组件标签上监听这个事件
parent.xml
<view>
<child bind:myEvent="handleEvent"/>
</view>
child.js
methods: {
onClickTest(data) {
this.triggerEvent('myEvent', data)
}
}
- 兄弟组件通信
1). globalData
将数据挂载到 app.js,这种方式在开发中很常用。通过getApp(),我们能够在任何一个页面内访问到app实例。
app.js
App({
globalData:{
list:[]
}
})
page1.js
const app = getApp()
Page({
onLoad(){
app.globalData.list.push({
id: 10
})
}
})
page2.js
const app = getApp()
Page({
onLoad(){
console.log(app.globalData.list) // [{id:10}]
}
})
2). storage
storage并不是作为通信的主要方式。storage 主要是为了缓存数据,并且最多只能存储10M的数据,我们应该合理使用storage
wx.setStorageSync('timestamp', Date.now())
wx.getStorageSync('timestamp')
wx.removeStorageSync('timestamp')
3). eventBus
class EventBus {
constructor() {
this.cacheData= {}
}
on(eventName, fn) {
this.cacheData[eventName] = this.cacheData[eventName] || []
this.cacheData[eventName].push(fn)
}
emit(eventName, data) {
this.cacheData[eventName] = this.cacheData[eventName] || []
this.cacheData[eventName].forEach((fn) => fn(data))
}
off(eventName, fn) {
if (this.cacheData[eventName]) {
const currentIndex = this.findIndex(eventName, fn)
this.cacheData[eventName].splice(currentIndex, 1)
}
}
findIndex(eventName, fn) {
for (let i = 0; i < this.cacheData[eventName].length; i++) {
if (fn === this.cacheData[eventName][i]) {
return i
}
}
}
}
export default new EventBus()
page1.js
import eventBus from '@Utils/eventBus'
ready() {
eventBus.on('update:addSelected', this.handleUpdateAddSelected.bind(this))
eventBus.on('update:removeSelected', this.handleUpdateRemoveSelected.bind(this))
},
page2.js
import eventBus from '@Utils/eventBus'
methods: {
handleUpdateSelect() {
if(this.data.active) {
console.log(4)
eventBus.emit('update:removeSelected', this.data.name)
} else {
console.log(5)
eventBus.emit('update:addSelected', this.data.name)
}
}
}
2. 获取组件实例
可在父组件里调用 this.selectComponent ,获取子组件的实例对象。(插件的自定义组件将返回 null),调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component"),类似于vue的ref
// 父组件
Page({
data: {},
getChildComponent: function () {
const child = this.selectComponent('.my-component');
console.log(child)
}
})
3.生命周期
created相当于vue的beforeCreated
attached相当于vue的created
ready相当于vue的mounted
detached相当于vue的beforeDestory
4. behaviors
相当于vue的mixin,会在使用的时候把里面的数据和当前实例合并
单独的behaviors.js文件写法
module.exports = Behavior({
data: {},
...
})
observers数据监听(类似于vue的watch)
Component({
attached: function() {
this.setData({
numberA: 1,
numberB: 2,
})
},
observers: {
'numberA, numberB': function(numberA, numberB) {
// 在 numberA 或者 numberB 被设置时,执行这个函数
this.setData({
sum: numberA + numberB
})
}
}
})
4.给事件传递参数
使用data-属性,注意data-后面跟的必须是全小写的字符
<view class="network-debug-content-part-content" bindtap="handleRequestDataCopy" data-requestlist="aaa">
</view>
handleRequestDataCopy(event) {
console.log(event.currentTarget.dataset.requestlist, 'aaa')
}
5. 插槽
用法
<!-- 在组件的wxml中定义插槽 -->
<view>
<!-- 默认插槽 -->
<slot></slot>
<!-- 具名插槽 -->
<slot name="before"></slot>
<slot name="after"></slot>
</view>
<!-- 在页面组件中使用 -->
<dong my-class="add">
<text>默认的插槽</text>
<view slot="after">具名插槽</view>
<view slot="before">具名插槽</view>
</dong>
默认一个组件只支持一个插槽,如果想要使用多个插槽还需要在组件的js文件里配置options
Component({
options: {
multipleSlots: true
}
})
如果想要实现有slot的时候只显示slot里的内容,没有slot的时候显示默认内容,可以使用css3 empty来实现
<view class="has-next-box has-next-customer">
<slot></slot>
</view>
<view class="has-next-box has-next-default">
没有更多数据
</view>
.has-next-customer {
display: none;
}
.has-next-customer:not(:empty) {
display: block;
}
.has-next-customer:not(:empty)+.has-next-default {
display: none;
}
6. 微信小程序阻止触发父组件事件
将bindtap换成catchtap就可以
7. 对于key值不固定的对象在xml里遍历后想拿到每一个的key和value的方法
将一个键值对拆分成两个,将原来的key和value分别作为value
比如:
{a: 1},{b:2}
拆分成
{key1: a, key2: 1},
{key1: b, key2: 2}
7.template的使用
template主要是简化xml代码的,可以搭配behaviors对js重复代码进行复用
只要我们的xml文件里使用了<template name="模板名">就可以被使用
1).在当前页面使用
直接通过<template is="模块名 data={{数据}}">
2).在其他页面或者组件里使用
<import src="../network-debug/index.wxml" />
这里引入的l我们这个文件本身可以使xml文件,但是在import里必须写成wxml
<template is="模块名 data={{数据}}">
template模板里的方法需要在当前组件或者页面里写,如果很多地方都用到这些方法,我就就需要通过behavior引用这些方法。
问题:
1).解决弹窗层内容可拖动会底层内容跟着拖动的问题
一:给弹窗层组件设置一个catchtouchmove="ture"让它阻止父组件的touchmove;
这种情况下,我们弹窗层的touch事件也无法触发了
二:所以我们需要把弹窗层里的内容放到scroll-view组件里,这样它就可以拖动了;
因为scroll-view组件有回弹,所以如果我们底部有遮罩层的话,它拖动的时候会显示底部遮罩层的内容,所以我们需要给scroll-view标签设置背景色为我们的弹窗展示层的背景色(白色)
<block>
<view class="collapse-drawer" w:if="{{visible}}" catchtouchmove="ture">
<p-mask visible="{{visible}}" bindmasktap="handleHideMask" z-index="{{zIndex}}"/>
<view class="collapse-drawer-wrapper {{visible ? 'collapse-drawer-wrapper-enter' : ''}}" style="z-index: {{zIndex}}">
<view class="collapse-drawer-wrapper-header">
<slot name="header"/>
</view>
<scroll-view scroll-y="true" style="height: {{contentHeight}}" class="collapse-drawer-wrapper-scroll">
<slot/>
</scroll-view>
</view>
</view>
</block>
.collapse-drawer {
background: #fff;
border-radius: 20rpx 20rpx 0 0;
overflow: hidden;
&-wrapper {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #fff;
transform: translateY(100%);
transition: all .3s linear;
border-radius: 20rpx 20rpx 0 0;
overflow: hidden;
&.collapse-drawer-wrapper-enter {
transform: translateY(0);
}
&-scroll {
background: #fff;
}
}
}
2). 微信小程序的数据更新视图是只有当相关的data都变了视图才会变,如果只有一部分data变了,那么视图不会变
比如:
上面的item是data里的一项,它变了但是因为后面的requestItem.key(requestItem是另一个data里的一项)每次都是固定的,所以当前这个text也不会变
解决办法:对内层的wx:for遍历结构改成template的方式
网友评论