Vue3造轮子:Switch组件

326 阅读1分钟

什么是Switch组件

image.png

API 设计

Switch组件怎么用

  • <Switch value="true" /> value为字符串 "true"

  • <Switch value="false" /> value为字符串 "false"

  • <Switch :value=" true " /> value为布尔值 true

  • <Switch :value=" false "/> value为布尔值 false

总结:当value为字符"true"或布尔值true时,显示为开;其他情况一律显示为关

初始化Switch组件

创建/src/lib/Switch.vue

image.png

如何让圆圈滚到右边(用CSS transition)

使用CSS高级特效calc()

image.png

点击切换,并有动画

image.png

checked.value = !checked.value 是取checked.value的相反值。

有动画,只需要在CSS里面加上transition

image.png

添加value属性,添加input事件

<Switch value="xxx" @input="xxx = $event" />

如何让Switch接受value? 用props即可

如何让Switch 发出input事件? 用context.emit('input', xxx) 即可

Vue 3 编程模型

  • 内部数据 V.S. 父子数据

image.png

内部数据:相当于在一个内部封闭的盒子里,当点击的时候,会调用toggle,这个toggle会去修改他的checked,所有的数据都是在内部消化的,叫做内部数据

父子数据:相当于在一个有开口的盒子里,有入口有出口,内部数据跟外部有沟通关系,开始有一个value,点击之后,没有权限去管外部的数据,只能通过emit的'input'事件传给出口,@input拿到新的值,新的值赋值给value,这个value再次进到盒子里来

image.png

如何让Switch发出input事件

  • context.emit('input', xxx)

  • input是事件名,也可以将input改成其他的名字

  • $event 是尤雨溪创造的一个变量,$event的值是emit的第二个参数,emit(事件名,事件参数)

Vue3 新版 v-model用法

对【父子之间的数据交流】进行简化

  • 要求

属性名任意,假设为x;事件名必须为"update:x"

  • 效果

<Switch :value="y" @update:value="y = $event" />可以简写为<Switch v-model:value="y"/>

知识点总结

  • value="true":value="true"的区别

  • 使用CSS transition 添加过渡动画

  • 使用 ref 创建内部数据

  • 使用 :value@input 让父子组件进行交流(组件通信)

  • 使用 $event

  • 使用v-model

  • 框架就是把你框起来:不准改props

image.png

最终代码

Switch.vue

<template>
  <button @click="toggle" :class="{ checked: value }">
    <span></span>
  </button>
</template>
<script lang="ts">
import { ref } from "vue";
export default {
  props: {
    value: Boolean,
  },
  setup(props, context) {
    const toggle = () => {
      context.emit("update:value", !props.value);
    };
    return { toggle };
  },
};
</script>
<style lang="scss" scoped>
$h: 22px;
$h2: $h - 4px;
button {
  height: $h;
  width: $h * 2;
  border: none;
  background: gray;
  border-radius: $h/2;
  position: relative;
  > span {
    position: absolute;
    top: 2px;
    left: 2px;
    height: $h2;
    width: $h2;
    background: white;
    border-radius: $h2 / 2;
    transition: left 250ms;
  }
  &.checked {
    background: blue;
    > span {
      left: calc(100% - #{$h2} - 2px);
    }
  }
  &:focus {
    outline: none;
  }
}
</style>

SwitchDemo.vue

<template>
  <div>
    <Switch v-model:value="bool" />
  </div>
</template>

<script lang="ts">
import { ref } from "vue";
import Switch from "../lib/Switch.vue";
export default {
  components: { Switch },
  setup() {
    const bool = ref(false);
    return { bool };
  },
};
</script>