Vue:造轮子02---switch组件

483 阅读1分钟

switch组件

需求分析

  1. Switch 组件怎么用
<Switch value="true" /> value 为字符串 "true"
<Switch value="false" /> value 为字符串 "false"
<Switch :value="true" /> value 为布尔值 true
<Switch :value="false" /> value 为布尔值 false
  1. 总结
  • 当 value 为字符串 "true" 或布尔值 true 时,显示为开
  • 其他情况一律显示为关

switch.vue和switchDemo.vue

  1. 新建lib/switch.vue和switchDemo.vue。
  • 在switchDemo.vue引入switch.vue.
//switch.vue
<template>
  <div>switch</div>
</template>
<script lang="ts">
  export default {
  }
</script>
//switchDemo.vue
<template>
  <div>
    <Switch/>
  </div>
</template>
<script lang="ts">
  import Switch from '../lib/Switch.vue'
  export default {
    name: 'SwitchDemo',
    components: { Switch }
  }
</script>
  1. switch.vue
<template>
  <button @click="toggle" :class="{checked}"><span></span></button>
  <!--如果checked为true,button的class就有checked,否则就没有-->
</template>
<script lang="ts">
  import { ref } from 'vue'
  export default {
    setup() {
      const checked = ref(false)
      const toggle = () => {
        checked.value = !checked.value
      }
      return {checked, toggle}
    }
  }
</script>
<style lang="scss" scoped>
  $h: 22px;
  $h2: $h - 4px;
  button{
    height: $h;
    width: $h*2;
    border: none;
    background: grey;
    border-radius: $h/2;
    position: relative;
    cursor: pointer;
  }
  span{
    position: absolute;
    top: 2px;
    left: 2px;
    height: $h2;
    width: $h2;
    background:white;
    border-radius: $h2 / 2;
    transition: left .25s;
  }
  button.checked{
    background: blue;
  }
  button.checked > span {
    left: calc(100% - #{$h2} - 2px);
  }
  <!--去掉外围黑色的圈圈-->
  button:focus {
    outline: none;
  }
</style>

  • button中间的span是switch的圆点。
  • 实现圆点向右滚动动画:根据有没有选中,控制class,给class加不同的css
  • 动画效果:
transition: left .25s;
  • button加一个toggle函数,取反控制checked
// 点击之后span的css
  button.checked{
    background: blue;
  }
  button.checked > span {
    left: calc(100% - #{$h2} - 2px);
  }

自定义初始状态和监听最新的值

  1. 我们需要用户使用组件的时候可以自己设定一开始是开启的还是关闭的,所以我们需要绑定一个初始值value。
  2. 当我们修改开关状态的时候我们传入的value也要跟着修改,所以需要在父组件监听一个input事件,拿到新的value值,子组件触发这个input事件把新的value值传出去
<Switch value="xxx" @input="xxx = $event"/>

  • SwitchDemo.vue
<template>
  <div>
    <Switch :value="x" @input="x = $event"/>
  </div>
</template>
<script lang="ts">
  import Switch from '../lib/Switch.vue'
  import { ref } from 'vue'
  export default {
    name: 'SwitchDemo',
    setup() {
      const x = ref(true)
      return { x }
    },
    components: { Switch }
  }
</script>
  • 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 //switchDemo.vue传过来的value
    },
    setup(props: Prop, context: any) {
      const toggle = () => {
        context.emit('input', !props.value) // vue3新特性context.emit, 告诉父组件触发input事件,value取反
      }
      return {toggle}
    }
  }
</script>

  • switchdemo传value给switch,表示是否选中。通过toggle更改选中或者不选中。
  • 如何让Switch接受value? 使用props
  • vue3的setup(props,context):第二个参数.emit,里面有一个方法是emit(类似vue2里的this.$emit)。
  • $event就是最新的值(就是 !props.value)

vue3:v-model

要求:

    1. props属性名任意,假设为x
    1. 事件名必须为"update:x" Switch.vue(子组件)
 context.emit('update:value', !props.value)

SwitchDemo.vue(父组件)

<Switch :value="y" @update:value="y=$event"/>
// vue2中的写法
<Switch :value.sync="y"/>
// vue3中的写法
<Switch v-model:value="y"/>