组件封装 - 复选框组件

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

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

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
    评论
单选框是前端展现数据字典的一种形式,下拉列表、单选按钮组和复选框组都可以实现。下拉列表是最常用的,但是单选按钮组也是一种常用的形式。下面介绍一下Vue组件单选框的封装方法。 单选框组件封装需要考虑以下几个方面: 1. 组件的props需要包含一个list属性,用于传递选项列表。 2. 组件的props需要包含一个modelValue属性,用于传递当前选中的值。 3. 组件需要在点击选项时,通过emit事件将选中的值传递给父组件。 4. 组件需要在选项列表中循环渲染每个选项,并且根据当前选中的值来设置选项的样式。 下面是一个简单的单选框组件的实现: <<引用>> 子组件: <template> <div class="radio-group"> <div v-for="(item, index) in props.list" :key="index" class="radio-item" :class="{active: item.value === props.modelValue}" @click="handleClick(item.value)"> <span>{{ item.label }}</span> </div> </div> </template> <script setup lang="ts"> import { defineProps, defineEmits } from 'vue' const props = defineProps({ list: { type: Array, required: true }, modelValue: { type: [String, Number], required: true } }) const emit = defineEmits(['update:modelValue']) const handleClick = (value: string | number) => { emit('update:modelValue', value) } </script> <style scoped> .radio-group { display: flex; flex-wrap: wrap; } .radio-item { margin-right: 10px; margin-bottom: 10px; padding: 8px 16px; font-size: 14px; background-color: #f6f7f9; border: 1px solid #f6f7f9; cursor: pointer; } .radio-item.active { background-color: var(--cp-plain); border-color: var(--cp-primary); } </style> 在父组件中使用该组件时,只需要传递一个选项列表和一个modelValue属性即可。例如: <template> <div> <radio-group :list="options" v-model="selected"></radio-group> </div> </template> <script> import RadioGroup from './RadioGroup.vue' export default { components: { RadioGroup }, data() { return { options: [ { label: '选项1', value: '1' }, { label: '选项2', value: '2' }, { label: '选项3', value: '3' } ], selected: '1' } } } </script>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值