组件封装 - 复选框组件

复选框组件在日常的开发过程中, 也是一个很常见和常用的组件

这里我会使用两种方法来实现复选框组件的封装:

1. v-model

2. @vueuse/core

首先完成复选框组件的基础布局, 和点击切换状态的功能

思路分析:

1. 基础布局是由一个父盒子, 其中包含两个字体图标和一个默认插槽

2. 其中暴露一个点击事件 changeChecked , 用来修改字体图片的状态

3. 定义一个变量, 用户点击时; 对这个变量进行取反即可

<template>
  <div class="xtx-checkbox" @click="changeChecked">
    <i v-if="checked" class="iconfont icon-checked"></i>
    <i v-else class="iconfont icon-unchecked"></i>
    <span v-if="$slots.default"><slot /></span>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'XtxCheckbox',
  setup () {
    const checked = ref(false)
    const changeChecked = () => {
      checked.value = !checked.value
    }
    return { checked, changeChecked }
  }
}
</script>

<style scoped lang="less">
.xtx-checkbox {
  display: inline-block;
  margin-right: 2px;
  .icon-checked {
    color: @xtxColor;
    ~ span {
      color: @xtxColor;
    }
  }
  i {
    position: relative;
    top: 1px;
  }
  span {
    margin-left: 2px;
  }
}
</style>

现在我们就来使用第一种方法实现复选框组件的封装(v-model)

首先我们得知道, 在 Vue3 中 v-model 其实是 :modelValue(默认的) + :update:modelValue的组合

思路分析:

1. 父组件会定义一个响应式数据, 通过 v-model 的方式传给子组件

2. 那么, 子组件内部就需要进行接收(默认是 modelValue)

3. 因为, 父组件传入的是一个布尔值; 所以子组件不能直接进行修改(违背单项数据流)

4. 复选框组件内部, 重新定义一个变量(checked) 

5. 当 changeChecked 函数被调用的时候, 将 checked 的值 emit 出去

6. 可能在父组件中, v-model 依赖的值就发生了变化; 所以我们需要使用 watch 对父组件传入进来的值进行监听(且是立即执行)

7. 一旦传入的数据发生变化, 立即修改 checked 变量的值

比如说: 

页面中有一个复选框, 前端向后端发送请求获取数据; 后端返回的数据是需要将复选框选中的

所以, 前端需要修改父组件中 v-model 所依赖的值

依赖值一发生变化, 复选框组件内部记录的值难道不要跟着变吗?

<template>
  <div class="xtx-checkbox" @click="changeChecked">
    <i v-if="checked" class="iconfont icon-checked"></i>
    <i v-else class="iconfont icon-unchecked"></i>
    <span v-if="$slots.default"><slot /></span>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  name: 'XtxCheckbox',
  props: {
    modelValue: {
      type: Boolean,
      default: false
    }
  },
  setup (props, { emit }) {
    const checked = ref(false)
    const changeChecked = () => {
      checked.value = !checked.value
      emit('update:modelValue', checked.value)
    }

    watch(() => props.modelValue, (newVal) => {
      checked.value = newVal
    }, { immediate: true })

    return { checked, changeChecked }
  }
}
</script>
<XtxCheckbox v-model="flag"></XtxCheckbox>

<script>
export default {
  name: 'SubFilter',
  setup () {
    const flag = ref(false)

    return { filterData, filterLoading, flag }
  }
}
</script>

再来使用第二种方法实现复选框组件的功能(@vueuse/core)

<template>
  <div class="xtx-checkbox" @click="changeChecked">
    <i v-if="checked" class="iconfont icon-checked"></i>
    <i v-else class="iconfont icon-unchecked"></i>
    <span v-if="$slots.default"><slot /></span>
  </div>
</template>

<script>
import { useVModel } from '@vueuse/core'
export default {
  name: 'XtxCheckbox',
  props: {
    modelValue: {
      type: Boolean,
      default: false
    }
  },
  setup (props, { emit }) {
    // 得到 useVModel 包装之后的数据
    const checked = useVModel(props, 'modelValue', emit)
    const changeChecked = () => {

      // checked.value 相当于在做在使用父组件的数据
      // checked.value = newVal 相当于在做 emit 操作
      const newVal = !checked.value
      checked.value = newVal

      // 让复选框组件兼容 change 事件
      emit('change', newVal)
    }

    return { checked, changeChecked }
  }
}
</script>

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值