写组件从来就不是一件难事,如果非要说有什么实现障碍,懒算吗???
这是大致总结的一种组件编写思路 整个编写的过程也是按照这个流程来做的。
Paste_Image.png
需求
不管需求是来自于老板、产品亦或是设计师,总之他能讲出道理或者他能拍板,干就是了
设计图
Paste_Image.png交互说明
正常这个需要设计师或者产品(以下均简称设计)做出交互demo
因为有时候设计不亲自做交互效果的话 他不容易想到一些交互细节,比如
- 小图在左右滑动后是否要贴边
- 滑动速度怎么样
Paste_Image.png在做一些其他丰富的ui组件时 要考虑的细节会更多 如果有时间 并且又能做作出交互demo的话 能更早的确定细节 确定这个组件的需求边界 工程师能更清楚的提前构思组件💭
实现
分拆
写组件就像是造人,捡来树枝作出骨骼,拾起泥料作出皮肤,最后再给上一口的仙气
1⃣骨骼
说实话这是上周的某一天写的 然而现在让我回头看 已经不知道这画的标的是什么意思了
结构过程
大体结构就是
Paste_Image.png
我的习惯组件挂载点为一个容器结构(div) 里面再套一个组件实际的容器
对了要有一个图片查看的遮罩层 别忘了 同组件容器并列
2⃣长相很重要
不管你承认不承认 颜值的重要程度远超一般的辩论论题
开始给你的小人化妆了 用css让每个小块都排好 如果是更复杂的组件 那么要在样式上花费一段时间了 好在这个很简单……
这里主要用到了flex布局和overhidden 没了……没啥可说的……
3⃣这口仙气
你戳死人一下 他不会说 也不会动 你戳活人一下 他会骂你娘
正是有了交互才让组件有了灵气 变得好玩,使用事件来帮它搭上反射弧,接上神经
来分析下这个组件的交互状态
- 整个组件挂载容器上静止的
- 包裹小图的容器要能够滑动 左滑 右滑
- 每个小图要能够响应点击 打开遮罩层并显示大图
- 大图要响应点击 关闭自身
技术选型
技术哪有对错 组合都是哲学
咱们这里就是vue来做,能利用什么资源呢
- 单文件 .vue带来的编写组件的便利 模版 样式 交互 都可以写在属于这个组件的地盘
- vue-touch 基于hammerjs的移动端touch组件 可以很方便的实现左滑右滑 还有 tap
- watch 监控属性 可以很方便的对数据状态的改变作出相应动作
还有相当一部分童鞋不仔细看文档 文档真的是很重要
vue如何编写可复用组件
有了这些就足够了
�
代码清单
<template>
<!--swiper 容器 满宽-->
<div class="picswiper-container">
<div v-touch:swipeleft="onSwipeLeft" v-touch:swiperight="onSwipeRight" class="picswiper-wrapper" v-bind:style="transitionObj">
<div v-touch:tap="lookPic(pic)" class="picswiper-item" v-for="pic in piclist">
[站外图片上传中……(2)]
</div>
</div>
</div>
<div v-touch:tap="closeMark()" class="picviewer-mark" v-show="isLookPic">
[站外图片上传中……(3)]
</div>
</template>
<script>
export default{
props:["piclist","picflag"],
data(){
return{
transitionObj:{
'transition-duration':"1000ms",
'transform':"translate3d(0, 0, 0)"
},
$translateX:10,//阿里适配方案
swipeLeftCount:0,//滑动次数
$shouldSwipeCount:1,//滑了几次 默认为1
$picWidth:3,//每个小图的宽 rem
$picWrapperWidth:0,//组件容器的宽rem
isLookPic:false,//是否查看大图
curPic:""
}
},
methods:{
onSwipeLeft(eventObj){
let me = this;
//计算有几个图片块
if(me.swipeLeftCount!=me.$data.$shouldSwipeCount){
me.swipeLeftCount++
}
},
onSwipeRight(){
let me = this;
//计算有几个图片块
if(me.swipeLeftCount!=0){
--me.swipeLeftCount
}
},
lookPic(pic){
this.curPic = pic
this.isLookPic = true
},
closeMark(){
this.isLookPic = false
}
},
watch:{
/**
* 监控数据
* 根据当前第几次 来判断滑动方向
* 在piclist存在时 进行一些配置数据的初始化
* @param val
* @param oldVal
*/
swipeLeftCount(val,oldVal){
let me = this;
if(val>oldVal){//往左滑
me.transitionObj.transform="translate3d(-"+me.$data.$translateX*val+"rem, 0, 0)"
}else if(val<oldVal){//向右滑
if(me.$data.$translateX/val=="Infinity"){//到头了
me.transitionObj.transform="translate3d(0, 0, 0)"
}else{
me.transitionObj.transform="translate3d(-"+me.$data.$translateX/val+"rem, 0, 0)"
}
}
},
/**
* 监控数据
* 在piclist存在时 进行一些配置数据的初始化
* @param val
* @param oldVal
*/
piclist(val,oldVal){
let me = this;
if(!!val){
me.$data.$picWrapperWidth = val.length*me.$data.$picWidth;
me.$data.$shouldSwipeCount = Math.floor(me.$data.$picWrapperWidth/me.$data.$translateX)
}
}
}
}
</script>
<style scope>
.picswiper-container {
width:100%;
height:2.666666667rem;
overflow: hidden;
}
.picswiper-wrapper {
position: relative;
width: 100%;
height: 100%;
z-index: 1;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-transition-property: -webkit-transform;
-ms-transition-property: -ms-transform;
transition-property: transform;
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
.picswiper-item {
width:2.666666667rem;
height:auto;
-webkit-flex-shrink: 0;
-ms-flex: 0 0 auto;
flex-shrink: 0;
position: relative;
text-align: center;
font-size: 18px;
background: #fff;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin-right: 0.2rem;
overflow: hidden;
}
.picviewer-mark {
position: fixed;
top: 0;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 20009;
background: rgba(0,0,0,0.8);
padding-top: 50%;
text-align: center;
}
</style>
怎么算完了?
- 完备测试
- 代码规范优化 包括书写优化 复用优化
- 性能有没有优化的
- 文档补充等等等
对这个组件来说,可优化的点太多了 包括配置项对外暴露 适配方案的兼容 图片数量测试等等,只是想借这个例子记录下写组件的思路
结语
写代码往往很快 思考怎么写往往费力 但也最为好玩
enjoy in think no matter what you do
网友评论