vi-motion 组件介绍
vi-motion
组件的内部运动是css3
动画,使用的是animate开源动画库
vi-motion
的出现是为了解决小程序开发时的复杂运动会话框。让开发不必把精力放在复杂的动画运动上,使其更加关注业务逻辑组件文档:vi-motion https://www.npmjs.com/package/vi-motion
github仓库:VisionUI, 欢迎 start 或 issues https://github.com/AsherSun/VisionUI
明确组件需求及使用场景
复杂的运动会话弹窗
多适用于授权弹窗、儿童类小程序项目、抽奖类小程序项目等
只定制运动动画,不提供任何UI界面
DOM结构设计
在上一步我们清楚的知道了组件的使用场景以及一些需要对外提供的接口
那么DOM结构(wxml)应该怎么设计呢?
既然这是一个运动类的会话弹窗,那么DOM结构与普通的会话弹窗是差不多的。一个根元素下面包含两个子元素。其中一个子元素为弹窗的mask遮罩层,一个元素是用来装载与用户的对话内容。
但是,该组件只是提供弹窗的运动方式,而不会提供弹窗的基本交互UI。所以,需要定义一个 slot 插槽用来接收开发者提供的对话UI界面
组件的内部DOM结构(wxml)
isShow
是用来控制组件的显示与隐藏
maskIsHide
用来控制遮罩层的显示与隐藏
maskColor
用来定义遮罩层的颜色
enterAnimateName
用来控制组件出现时候的动画
outAnimateName
用来控制组件隐藏时候的动画
animationDuration
用来控制动画运动的时间
<view wx:if="{{isShow}}" class="vi-dialog">
<view
class="vi-dialog-mask"
wx:if="{{!maskIsHide}}"
data-sign="mask"
capture-catch:tap="triggerToHide"
style="background-color: {{maskColor}}">
</view>
<view
class="animated {{ishide ? enterAnimateName : outAnimateName}} container-calss"
style="animation-duration: {{animationDuration}}s">
<slot></slot>
</view>
</view>
基本的DOM结构出来之后,下面是给这些DOM结构编写style
我们会在样式文件(wxss)中引入animate开源动画库
@charset "UTF-8";
@import './animate.min.wxss';
.vi-dialog {
top: 0;
left: 0;
position: fixed;
height: 100%;
width: 100%;
box-sizing: border-box;
z-index: 10000;
}
.vi-motion__animated {
transition-property: transform;
transition-delay: 0.5s;
}
.vi-dialog-mask {
background-color: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 9999;
}
组件的行为开发
在组件的DOM结构上,我们基本定义了一些对外的接口用来控制组件的行为表现
这些接口分别为:
ishide
、maskIsHide
、maskColor
、enterAnimateName
、outAnimateName
、animationDuration
等
在清楚了一些基本接口的设计之后,我们就可以在 Component构造器中定义接口了
Component({
properties: {
ishide: {
type: Boolean,
value: false,
observer(newValue) {
},
enterAnimateName: {
type: String,
value: 'bounce'
},
maskIsHide: {
type: Boolean,
value: false
},
outAnimateName: {
type: String,
value: ''
},
maskColor: {
type: String,
value: 'rgba(0,0,0, .3)'
},
animationDuration: {
type: Number,
value: 1
}
},
})
接口定义完成已经基本可以控制弹窗的现实、隐藏。但是我们在wxml结构中用 wx:if="{{isShow}}"
语句来控制组件的显示与隐藏的。为什么在接口定义的部分没有看到呢?其实是有原因的,说清楚原因我们再继续之后的开发
没有定义isShow接口的原因有:
wx:if语句是直接控制元素的显示隐藏,在组件进入页面的时候会有动画,但是如果组件隐藏的时候也需要动画呢?
组件在隐藏的时候如果有动画,那么就必须要等动画运动结束才可以让组件隐藏
基于上面的这两个原因,我们把isShow字段放在data对象上
Component({
properties: {
ishide: {
type: Boolean,
value: false,
observer(newValue) {
if (newValue) {
this.setData({
isShow: newValue
});
} else {
setTimeout(() => {
this.setData({
isShow: newValue
});
}, this.data.animationDuration * 1000)
}
}
},
...
},
data: {
isShow: false
}
})
那既然解决了组件隐藏时动画的展示。但是,如果在组件隐藏的时候就是不想要动画呢?基于这样的需求,于是我们再定义一个接口,用来控制组件隐藏的时候是否出现动画
Component({
properties: {
ishide: {
type: Boolean,
value: false,
observer(newValue) {
if (this.data.outHasAnimate) {
if (newValue) {
this.setData({
isShow: newValue
});
} else {
setTimeout(() => {
this.setData({
isShow: newValue
});
}, this.data.animationDuration * 1000)
}
} else {
this.setData({
isShow: newValue
});
}
}
},
outHasAnimate: {
type: Boolean,
value: true
},
...
},
data: {
isShow: false
}
})
现阶段,我们定义了组件的行为接口。那如果是这样的业务场景:用户点击 mask 遮罩层,需要隐藏组件。那么我们就需要监听mask 遮罩层的点击事件
Component({
methods: {
triggerToHide(e) {
this.triggerEvent('hide', this.data.ishide)
}
},
})
上面是mask遮罩层的点击方法,然后用 this.triggerEvent()
自定义一个事件。之后在页面中调用 hide
自定义事件就可以达到监听组件的mask元素的点击事件。
但是,如果产品提出了这样的需求:点击遮罩层不能隐藏组件。我们大可以不必在页面中调用组件的自定义事件,我们也可以再定义一个接口,用于表示是否触发组件的自定义事件
Component({
properties: {
clickMaskHide: {
type: Boolean,
value: false
},
...
},
methods: {
triggerToHide(e) {
if (this.data.clickMaskHide) return false;
this.triggerEvent('hide', this.data.ishide)
}
}
})
写到这,副本基本算是通关了,可以收功了。但我们好像还遗漏了一个页面布局相关的“小怪“。因为该组件的使命是提供多种运动方式,所以不会定义用于装载内容盒子的样式。所以我们需要暴露一个样式扩展的接口。
由于小程序框架本身的限制,在页面中是无法更改组件的内部元素的样式,所以小程序提供了一个接口:externalClasses
Component({
properties: {
...
},
externalClasses: ['container-class'],
methods: {
...
},
data: {
...
}
})
在页面的元素中用 class
属性来接收组件外部的自定义样式
<view
class="container-calss ... "
style="animation-duration: {{animationDuration}}s">
<slot></slot>
</view>
写在最后的提示:由于组件的运动方式是使用的animate开源动画库,所以
container-class
接口定义的样式不能使用css3的transform
组件效果预览与微信公众号