神了!!看完这篇文章我不仅学会了手撸vue三开关组件,还搞懂了父子组件传值

  • 引子
  • 前置知识
    • 什么是vue组件
    • 父子组件传值
      • 父传子
      • 子传父
      • model选项的引入
  • 三开关组件(three-switch)
    • 第一版:vant版
    • 第二版:动画流畅版
    • 第三版:逻辑优化版
    • 第四版:传值优化版

引子

这段时间在做公司的项目的时候遇到筛选功能的编写,分为三种状态[未评价,已评价,全部]。平时其实都是做下拉框来解决这个问题,但是在这个筛选弹窗里做下拉框整体又不太美观。同事最开始使用的vant的switch组件,但是这个组件只有true和false两种状态,并没有完全的满足需求,我找了大部分框架都没找到threeSwitch,于是自己动手撸了一个。

我们先来看看效果吧:

在正式讲解三开关组件之前,先介绍几个前置知识

前置知识

什么是vue组件

组件是可复用的 Vue 实例, 把一些公共的模块抽取出来,然后写成单独的的工具组件或者页面,在需要的页面中就直接引入即可那么我们可以将其抽出为一个组件进行复用。例: 页面头部、侧边、内容区,尾部,上传图片,等多个页面要用到一样的就可以做成组件,提高了代码的复用率。(直接引用啦)

父子组件传值

只写组件当然不行,组件之间的通信才是灵魂

父传子

在子组件使用props选项,接收父组件传来的值

子组件child.vue
<template><div><h3>父组件传值</h3><div>{{father}}</div></div>
</template>
<script>export default {props:{father:{type:String,default:'空'}}}
</script>
父组件father.vue
<template><div style="text-align: center;"><child :father="father"></child><button @click="change">点击传值</button></div>
</template><script>import child from './components/child/child.vue'export default {components: {child},data() {return {father: '空'}},methods:{change(){this.father='这是父组件传来的值'}}}
</script>

子传父

使用emits方法向父组件传值

子组件child.vue
<template><div><h3>子组件传值</h3><button @click="change">点击传值</button></div>
</template>
<script>export default {methods:{change(){this.$emit('change','子组件传值')}}}
</script>
父组件father.vue
<template><div style="text-align: center;"><child @change='change'></child><div>{{child}}</div></div>
</template>
<script>import child from './components/child/child.vue'export default {components: {child},data() {return {child: '空'}},methods:{change(data){this.child=data}}}
</script>

model选项的引入

通过上面的基本了解,现在我们已经知道如何进行父子组件间的通信了,但是对于一些组件,比如表单元素,我们是需要值的双向绑定的,通过model选项的引入,我们可以实现值的双向绑定,当然要实现父组件的动态传值,子组件是需要使用watch来监听父组件的传值变化的

父组件father.vue
<template><div id="app" style="text-align: center;"><h3>model双向绑定-父组件</h3><div>{{father}}</div><button @click="change">点击改变值</button><child v-model="father"></child></div>
</template><script>import child from './components/child/child.vue'export default {components: {child},data() {return {father: 0}},methods:{change(){this.father+=1}}}
</script>
子组件child.vue
<template><div><h3>model双向绑定-子组件</h3><button @click="change">点击改变值</button><div>{{child}}</div></div>
</template>
<script>export default {props:{father:{type:Number,default:0}},data(){return{child:0}},created() {this.child=this.father},model:{prop:'father',event:'change'},watch:{father(newVal){this.child=newVal}},methods:{change(){this.child+=1this.$emit('change',this.child)}}}
</script>

三开关组件(three-switch)

终于讲到了三开关组件,最开始写这个组件的时候我是参考了vant,但是这样写出来圆点和进度条的滑动有延迟,最后我改了大概四版的样子,最后写出了自己最满意的那一版,下面分别这四版的演变,希望能给大家一些启示吧

第一版:vant版

这一版主要参考了vant的动画,但是逻辑二开关与三开关不太一样,逻辑上参考较少,动画的思路大致如下:
将组件分为两层:第一层背景(固定长宽的弧形框)、第二层滑动条与圆点。然后让滑动条与圆点同时滑动,但这样其实是有延迟的,二者的收缩速率并没有办法保持一致。代码在更改后未保存,大家可以自己实现一下。

第二版:动画流畅版

这一版在动画上做了改进,灵感来源于我的好兄弟,在参考他的思路后,我写出了第二版,这一版动画非常的流畅,可以说是已经实现了文章最初的gif图中的样子,但是还有一些缺陷。现在讲讲如何改进的动画:
将之前的两层结构换成了三层结构:第一层背景、第二层滑动条、第三层圆点。然后给圆点加上了 {dispaly:absolute;right:0;},非常简单的改动,但是实现了动画的流畅。

第三版:逻辑优化版

在此之前的版本中,逻辑其实都很复杂,判断做的很多,基本的逻辑是:

  • 如果圆点是在最左边,那么滑动的方向只能向右;
  • 如果圆点是在最右边,那么滑动的方向只能向左;
  • 如果圆点是在中间,那么根据上一次滑动的方向来判断向哪边滑动,如果是上一次是向右滑动,那么这一次也向右,如果上一次是向左滑动,那么这一次也向左滑动。

但是这样的话每一次滑动其实要做三次判断,这样的效率是很低的,虽然现在计算机硬件很牛,这样的运算很快就能计算出来,但是我还是希望能够将这种变化优化到每次最多只需要判断两次,大多数情况下只需要判断两次,且简化运算。想了很久后,我的思路是这样的:

  • 将三种状态分别定义为了数字:-1,0,1
  • 每次更新状态,先判断方向,若圆点在最左边或者最右边就换向,使用if-else减少判断次数
  • 判断三开关状态:-1/0/1,若方向为右,则状态+1,若方向为左,则状态-1
  • 将滑动条的长度变为动态更新,将其长度与变量stripWidth绑定,这样更新stripWidth即可更行滑动条长度,使其滑动
  • 向父组件传输更新的状态

函数代码如下:

changeStatus() {if(this.checkValue===1)this.direct=0else if(this.checkValue===-1)this.direct=1this.checkValue=this.direct===1?this.checkValue+1:this.checkValue-1this.stripWidth = (2+this.checkValue) * this.sizethis.$emit("change", this.checkValue)
}

第四版:传值优化版

在之前的版本中其实我一直没有成功实现动态更新传值,在这个版本中我引入了watch和model实现了传值的优化。
到此其实已经实现了真正开发一个组件库中的组件的80%的工作,若要开发组件库,还需要将此代码封装,以提高引用的效率和后期维护。
接下来细致的描述一下组件编写的过程:

  • 编写大致的框架,在这个组件中,我首先会编写如下代码:
<template><div class="root"><div class="strip"><div class="node"></div></div></div>
</template><script>export default {}
</script><style scoped lang="scss">
</style>
  • 编写大致的样式
<style scoped lang="scss">.root {position: relative;display: inline-block;box-sizing: content-box;font-size: 30px;background-color: white;border: 1px solid rgba(221, 221, 221, 1.0);cursor: pointer;}.node {position: absolute;top: 0;right: 0;background-color: white;border-radius: 100%;box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05),0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);}.strip {position: absolute;top: 0;left: 0;background: rgba(95, 184, 120, 1);transition: width 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);}
</style>
  • 构思逻辑,然后编写方法,方法的思路在上面已经提到了,最终完善组件,组件代码如下:
threeSwitch.vue
<template><div class="root" @click="changeStatus":style="{ width: rootWidth + 'em', height: height + 'em',borderRadius:radius+'em' }"><div class="strip" :style="{ width: stripWidth + 'em', height: height + 'em',borderRadius:radius+'em' }"><div class="node" :style="{ width: nodeWidth + 'em', height: height + 'em' }"></div></div></div>
</template><script>export default {props: {size: {type:String,default:1},check: {type:Number,default:-1}},data() {return {ismid: true,isright: false,rootWidth: 3,height: 1,stripWidth: 1,nodeWidth: 1,radius: 1,direct: 1,checkValue: -1}},methods: {changeStatus() {if(this.checkValue===1)this.direct=0else if(this.checkValue===-1)this.direct=1this.checkValue=this.direct===1?this.checkValue+1:this.checkValue-1this.stripWidth = (2+this.checkValue) * this.sizethis.$emit("change", this.checkValue)}},model: {prop: 'check',event: 'change'},created() {if(this.check==1)this.direct = 0this.checkValue=this.checkthis.stripWidth = (2+this.checkValue) * this.sizethis.rootWidth *= this.sizethis.height *= this.sizethis.nodeWidth *= this.sizethis.radius *= this.size}}
</script><style scoped lang="scss">.root {position: relative;display: inline-block;box-sizing: content-box;font-size: 30px;background-color: white;border: 1px solid rgba(221, 221, 221, 1.0);cursor: pointer;}.node {position: absolute;top: 0;right: 0;background-color: white;border-radius: 100%;box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05),0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);}.strip {position: absolute;top: 0;left: 0;background: rgba(95, 184, 120, 1);transition: width 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);}
</style>

引用组件的示例如下:

<template><div id="app" style="text-align: center;"><three-switch v-model="check" size="4"></three-switch><div style="font-size: 100px;">{{check}}</div></div>
</template><script>import threeSwitch from './components/threeSwitch/threeSwitch.vue'export default {components: {threeSwitch,},data() {return {check: 1,}}}
</script>

demo下载地址

神了!!看完这篇文章我不仅学会了手撸vue三开关组件,还搞懂了父子组件传值相关推荐

  1. 如何 DIY 一款属于自己的【3D 重力感应 动态壁纸 】,看完这篇文章你也可以学会

    文章目录 ??前言 ??Unity实战篇 | unity制作动态壁纸,一款支持 DIY的[重力感应 的 3D动态壁纸] 制作过程 ??新建一个Unity工程,导入壁纸插件 ??导入Unity的模型素材 ...

  2. 音频如何转换成文字格式?看完这篇文章你就学会操作了

    在平时的工作中,想必大家都会使用一些录音工具来将会议的内容进行录制,事后再根据录音来整理会议的纪要,但如果一边听一边整理的话,有时可能会因为演讲者的语速过快而导致遗漏了一些内容. 其实这个时候我们可以 ...

  3. 看完这篇文章后,你一定知道如何正确选股!

    看完这篇文章后,你一定知道如何正确选股!篇幅很长,但是都是干货,请耐心阅读! 选股应该博爱!真正的股票投资人一定是拥有博爱情怀的.很多时候,股民们纠结于某只或某几只股票不能自拨,导致频频在股市中吃亏碰 ...

  4. python装饰器原理-看完这篇文章还不懂Python装饰器?

    原标题:看完这篇文章还不懂Python装饰器? 1.必备 2.需求来了 初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作.redis调用.监控API等功能.业务部门 ...

  5. 看完这篇文章之后,终于明白了编译到底怎么回事。

    看完这篇文章之后,终于明白了编译到底怎么回事. 1 对于同一个语句,有如下三种:高级语言.低级语言.机器语言的表示 C语言  a=b+1; 汇编语言  mov -0xc(%ebp),%eax add ...

  6. 看完这篇文章之后,终于明白了编译到底怎么回事

    看完这篇文章之后,终于明白了编译到底怎么回事. 1 对于同一个语句,有如下三种:高级语言.低级语言.机器语言的表示 C语言  a=b+1; 汇编语言  mov -0xc(%ebp),%eax add ...

  7. html5 游戏前景怎么样,独家 HTML5游戏目前究竟怎么样?看完这篇文章,你或许会清晰很多...

    原标题:独家 HTML5游戏目前究竟怎么样?看完这篇文章,你或许会清晰很多 文/DataEye CEO 汪祥斌 从5月份白鹭的10亿估值,到最近悟空间.山水地.火缘步甲的千万级以上的融资,我们可以感受 ...

  8. 手把手教你完成CSDN对接百度统计 看完这篇文章你还不会对接 欢迎您提刀顺着网线来砍我!!!!

    大家好,我是:じ☆ve朽木,开发经验都是一步一步慢慢积累的,没有谁生来就具有的,只要我们付出了努力,肯定就会有收获!进入我的博客,带你了解Java知识,js小技巧,带你玩转高端物联网.博客地址为:じ☆ ...

  9. 看完这篇文章,还不懂nginx,算我输

    看完这篇文章,还不懂nginx,算我输 参考:https://mp.weixin.qq.com/s/PeNWaCDf_6gp2fCQa0Gvng 1. Nginx产生~ Nginx 同 Apache ...

最新文章

  1. 如何理解Nyquist采样定理?
  2. pandas使用apply函数:在dataframe数据行(row)上施加(apply)函数
  3. 14.8.4 Moving or Copying InnoDB Tables to Another Machine 移动或者拷贝 InnoDB 表到另外机器...
  4. php 注册树,php设计模式-注册树模式
  5. oracle group by ,having ,order by
  6. iOS Cookie学习(NSHTTPCookieStorage的使用)
  7. Oracle中主键自增长
  8. 谷歌笔试题(Google十二岁生日晚)
  9. [转] new 和delete
  10. 激活层是每一层都有吗_每一个日出日落,都是岁月痕迹。这些在东软的第一次,你还记得吗...
  11. [渝粤教育] 西南科技大学 管理学原理 在线考试复习资料(4)
  12. 使用ajaxfileupload.js上传文件成功之后,没有执行success方法
  13. tableau示例超市数据在哪儿_Tableau | 超市销售数据可视化分析
  14. php商家商城,PHP红色小京东多商家入驻商城带移动端运营版
  15. 产品经理认证(NPDP)知识体系指南.2017
  16. 【梳理】离散数学 第15章 欧拉图与哈密顿图 15.3 最短路问题、中国邮递员问题与货郎担问题
  17. Nginx的HTTP健康检测
  18. ASP.NET20003人事薪资管理系统
  19. pixi 小游戏_关于PIXI引擎制作页面小游戏的几个总结
  20. 软件构造设计模式III(转载整合)

热门文章

  1. 四川省工程造价咨询服务收费标准川价发2008-141
  2. ubuntu如何删除文件夹?
  3. 64位Windows 7 中最好的杀毒软件!
  4. 划词搜索被ewido视为高风险Adware.wSerarch
  5. 手机装Linux开mc服务器,在Debian Linux上开启MineCraft(MC)服务器的1点经验
  6. linux xenserver教程,XenServer常用命令
  7. 【diannaoxitong】总结网站被百度K站怎么快速恢复的方法
  8. Linux 静态库和共享(动态)库的创建与使用详解
  9. 【1419. 数青蛙】
  10. linux ubuntu 玩游戏