为什么要造轮子
老实说,我们自己花时间去造的一个轮子,有很大的概率是不如网上现成的组件库。因为这些开源组件库有团队维护,也经过了市场的检验!
但是从历练自身这角度来看,我们一直在用别人的东西,或者别人的组件不能满足自身项目的需求,那这个时候如果你有造轮子的能力,解决过类似的问题,你就会比他人更有优势。在造轮子的过程中,还可以跟一些优秀的组件源码进行比较,进而更好的了解其中优良的设计和优秀的写法!
所以……我们开始造轮子系列第一篇-switch
先看一下咱们要做的switch的效果
思路
样式:一个button
包裹一个span
功能:<Switch v-model:checked="value" />
value
控制switch的状态
步骤
码云代码仓库
在src
目录下面新建文件夹lib
存储组件Switch.vue
在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-xxx
,data-v-xxx
中的xxx
每次运行可能不同
必须输出稳定不变的class选择器,方便使用者覆盖
必须加前缀
所有组件库的class类必须加上组件前缀,比如.switch
变成.bt-switch
防止被使用者覆盖
v-model的使用
v-model
是 vue
的语法糖,vue3
合并了vue2
的v-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