造轮子系列之switch

为什么要造轮子

老实说,我们自己花时间去造的一个轮子,有很大的概率是不如网上现成的组件库。因为这些开源组件库有团队维护,也经过了市场的检验!

但是从历练自身这角度来看,我们一直在用别人的东西,或者别人的组件不能满足自身项目的需求,那这个时候如果你有造轮子的能力,解决过类似的问题,你就会比他人更有优势。在造轮子的过程中,还可以跟一些优秀的组件源码进行比较,进而更好的了解其中优良的设计和优秀的写法!
所以……我们开始造轮子系列第一篇-switch

先看一下咱们要做的switch的效果

造轮子系列之switch

思路

样式:一个button包裹一个span

功能:<Switch v-model:checked="value" /> value控制switch的状态

步骤

码云代码仓库

初始代码 最终代码 commit记录

src目录下面新建文件夹lib存储组件Switch.vue

造轮子系列之switch

components下的 SwitchDemo.vue组件中引入

<template>
  <div>
    <Switch></Switch>
  </div>
</template>
<script lang="ts" setup>
import Switch from '../lib/Switch.vue'
</script>

Switch.vue样式

样式思路:button包含span标签(圆圈),控制span标签的left值,控制span的移动

<template>
  <div class="bt-switch">
    <button class="checked">
      <span></span>
    </button>
  </div>
</template>
<script lang="ts" setup></script>
<style lang="scss">
.bt-switch {
  button {
    $h: 22px;
    $h2: $h - 4px;
    width: 2 * $h;
    height: $h;
    border-radius:($h / 2);
    border: none;
    position: relative;
    background: #bfbfbf;
    > span {
      background-color: red;
      width: $h2;
      height: $h2;
      border-radius: ($h2/2);
      position: absolute;
      left: 2px;
      top: 2px;
      transition: all 0.25s;
      background: #fff;
    }
    &.checked {
      background-color: #1890ff;
    }
    &.checked > span {
      left: calc(100% - #{$h2} - 2px);
    }
    &:focus{
      outline: none;
    }
    &:active > span {
      width: $h2 + 4px;
    }
    &.checked:active > span {
      left: calc(100% - #{$h2} - 6px);
      margin-left: -4px;
    }
  }
}
</style>

Switch.vue功能

v-model控制checked的值

src/components/SwitchDemo.vue代码

<template>
  <div>
    <Switch v-model:checked="value"></Switch>
  </div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Switch from '../lib/Switch.vue'
const value = ref(true)
</script>

src/lib/Switch.vue代码

<template>
  <div class="bt-switch">
    <button @click="toggle" :class="{checked}">
      <span></span>
    </button>
  </div>
</template>
<script lang="ts" setup>
const props = defineProps({
  checked: {
    type: Boolean,
    default: true
  }
})
const emit = defineEmits(['update:checked'])
const toggle = () => {
  console.log(props.checked)
  emit('update:checked', !props.checked)
}
</script>

知识点回顾

组件库中的CSS不能使用scoped

因为如果加上scoped,样式的class就会变成data-v-xxxdata-v-xxx中的xxx每次运行可能不同

必须输出稳定不变的class选择器,方便使用者覆盖

必须加前缀

所有组件库的class类必须加上组件前缀,比如.switch变成.bt-switch防止被使用者覆盖

v-model的使用

v-modelvue的语法糖,vue3合并了vue2v-model.sync功能,感兴趣的可以去官网查看

calc的用法

calc使用scss变量的时候必须calc(100% - #{$h2} - 6px);这样写

踩坑

props必须下面这样写

const props = defineProps({
    checked: {
    type: Boolean,
    default: true
  }
})

如果这样写会有问题

const { checked } = defineProps({
    checked: {
    type: Boolean,
    default: true
  }
})

这样写不是响应式的

原文链接:https://juejin.cn/post/7234058802743885884 作者:JoyZ

(0)
上一篇 2023年5月17日 上午11:15
下一篇 2023年5月18日 上午10:05

相关推荐

发表回复

登录后才能评论