温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Vue封装数字框组件如何实现

发布时间:2023-04-20 09:29:46 阅读:153 作者:iii 栏目:开发技术
Vue开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

本篇内容介绍了“Vue封装数字框组件如何实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

数量选择组件-基本结构

(1)准备基本结构

<script lang="ts" setup name="Numbox">
//
</script>
<template>
  <div class="numbox">
    <div class="label">数量</div>
    <div class="numbox">
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >-</a>
      <input type="text" readonly value="1" />
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >+</a>
    </div>
  </div>
</template>
<style scoped lang="less">
.numbox {
  display: flex;
  align-items: center;
  .label {
    width60px;
    color#999;
    padding-left10px;
  }
  .numbox {
    width120px;
    height30px;
    border1px solid #e4e4e4;
    display: flex;
    > a {
      width29px;
      line-height28px;
      text-align: center;
      background#f8f8f8;
      font-size16px;
      color#666;
      &:first-of-type {
        border-right1px solid #e4e4e4;
      }
      &:last-of-type {
        border-left1px solid #e4e4e4;
      }
    }
    > input {
      width60px;
      padding0 5px;
      text-align: center;
      color#666;
    }
  }
}
</style>

(2)全局注册

import Numbox from '@/components/numbox/index.vue'
export default {
  install(app: App) {
    app.component('Numbox'Numbox)
  },
}

(3)提供类型声明

import Numbox from '@/components/numbox/index.vue'
declare module 'vue' {
  export interface GlobalComponents {
    Numboxtypeof Numbox
  }
}
export {}

(4)渲染

<div class="spec">
  <!-- 数字选择框 -->
  <XtxNumbox></XtxNumbox>
</div>

效果

Vue封装数字框组件如何实现

数量选择组件-v-model语法糖

目标:掌握vue3.0的v-model语法糖原理

在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />

在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

演示代码:

<script lang="ts" setup>
defineProps({
  money: {
    typeNumber,
    default0,
  },
})
const emit = defineEmits(['update:money'])
</script>
<template>
  <h4>子组件-{{ money }}</h4>
  <button @click="emit('update:money', money + 1)">+1</button>
</template>
<style scoped lang="less"></style>

总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue

补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx 子传父 @update:xxx 在vue3.0 使用 v-model:xxx 代替。

数量选择组件-功能实现

大致功能分析:

  • 默认值为1

  • 可限制最大最小值

  • 点击-就是减1 点击+就是加1

  • 需要完成v-model得实现

  • 存在无label情况

<script lang="ts" setup name="Numbox">
const props = defineProps({
  modelValue: {
    typeNumber,
    default1,
  },
  min: {
    typeNumber,
    default1,
  },
  max: {
    typeNumber,
    default20,
  },
  showLabel: {
    typeBoolean,
    defaultfalse,
  },
})
const emit = defineEmits<{
  (e'update:modelValue'value: number): void
}>()
const add = () => {
  if (props.modelValue >= props.maxreturn
  emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
  if (props.modelValue <= props.minreturn
  emit('update:modelValue', props.modelValue - 1)
}
</script>
<template>
  <div class="numbox">
    <div class="label" v-if="showLabel"><slot>数量</slot></div>
    <div class="numbox">
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="sub">-</a>
      <input type="text" readonly :value="modelValue"/>
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="add">+</a>
    </div>
  </div>
</template>
<style scoped lang="less">
.numbox {
  display: flex;
  align-items: center;
  .label {
    width60px;
    color#999;
    padding-left10px;
  }
  .numbox {
    width120px;
    height30px;
    border1px solid #e4e4e4;
    display: flex;
    > a {
      width29px;
      line-height28px;
      text-align: center;
      background#f8f8f8;
      font-size16px;
      color#666;
      &:first-of-type {
        border-right1px solid #e4e4e4;
      }
      &:last-of-type {
        border-left1px solid #e4e4e4;
      }
    }
    > input {
      width60px;
      padding0 5px;
      text-align: center;
      color#666;
    }
  }
}
</style>

动态控制禁用效果

<script lang="ts" setup name="Numbox">
const props = defineProps({
  modelValue: {
    typeNumber,
    default1,
  },
  min: {
    typeNumber,
    default1,
  },
  max: {
    typeNumber,
    default20,
  },
  showLabel: {
    typeBoolean,
    defaultfalse,
  },
})
const emit = defineEmits<{
  (e'update:modelValue'value: number): void
}>()
const add = () => {
  if (props.modelValue >= props.maxreturn
  emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
  if (props.modelValue <= props.minreturn
  emit('update:modelValue', props.modelValue - 1)
}
</script>
<template>
  <div class="numbox">
    <div class="label" v-if="showLabel"><slot>数量</slot></div>
    <div class="numbox">
     + <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="sub" :class="{not:props.modelValue <= props.main}">-</a>
      <input type="text" readonly :value="modelValue" />
     + <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="add" :class="{not:props.modelValue >= props.max}">+</a>
    </div>
  </div>
</template>
<style scoped lang="less">
.numbox {
  display: flex;
  align-items: center;
  .label {
    width60px;
    color#999;
    padding-left10px;
  }
  .numbox {
    width120px;
    height30px;
    border1px solid #e4e4e4;
    display: flex;
    > a {
      width29px;
      line-height28px;
      text-align: center;
      background#f8f8f8;
      font-size16px;
      color#666;
 +     &.not {
 +       cursor: not-allowed;
 +     }
      &:first-of-type {
        border-right1px solid #e4e4e4;
      }
      &:last-of-type {
        border-left1px solid #e4e4e4;
      }
    }
    > input {
      width60px;
      padding0 5px;
      text-align: center;
      color#666;
    }
  }
}
</style>

使用组件:src/views/goods/index.vue

<script lang="ts" setup name="Numbox">
import {ref} from "vue";
const count = ref(1)
</script>
<!-- 商品信息 -->
<div class="goods-info">
    <!-- 数字选择框 -->
    <XtxNumbox v-model="count" min:"1:max="20" ></XtxNumbox>
</div>

思考:

我们的输入框不仅能点击加减还可以输入数字,如果用户通过输入框输入非数字会出现什么问题?

Vue封装数字框组件如何实现

优化代码

<script lang="ts" setup name="Numbox">
const props = defineProps({
  modelValue: {
    typeNumber,
    default1,
  },
  min: {
    typeNumber,
    default1,
  },
  max: {
    typeNumber,
    default20,
  },
  showLabel: {
    typeBoolean,
    defaultfalse,
  },
})
+const { proxy } = getCurrentInstance() as ComponentInternalInstance
const emit = defineEmits<{
  (e'update:modelValue'value: number): void
}>()
const add = () => {
  if (props.modelValue >= props.maxreturn
  emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
  if (props.modelValue <= props.minreturn
  emit('update:modelValue', props.modelValue - 1)
}
+const handleChange = (e: Event) => {
+  // 通过类型断言,让ts知道目前元素的类型
+  const element = e.target as HTMLInputElement
+  let value = +element.value
+  if (isNaN(value)) value = 1
+  if (value >= props.max) value = props.max
+  if (value <= props.main) value = props.main
+  emit('update:modelValue',value)
+  // 强制刷新
+  proxy?.$forceUpdate()
}    
</script>
<template>
  <div class="numbox">
    <div class="label" v-if="showLabel"><slot>数量</slot></div>
    <div class="numbox">
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="sub" :class="{not:props.modelValue <= props.main}">-</a>
      <input type="text" readonly :value="modelValue" @change="handleChange($event)"/>
      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="add" :class="{not:props.modelValue >= props.max}">+</a>
    </div>
  </div>
</template>
<style scoped lang="less">
.numbox {
  display: flex;
  align-items: center;
  .label {
    width60px;
    color#999;
    padding-left10px;
  }
  .numbox {
    width120px;
    height30px;
    border1px solid #e4e4e4;
    display: flex;
    > a {
      width29px;
      line-height28px;
      text-align: center;
      background#f8f8f8;
      font-size16px;
      color#666;
      &.not {
        cursor: not-allowed;
      }
      &:first-of-type {
        border-right1px solid #e4e4e4;
      }
      &:last-of-type {
        border-left1px solid #e4e4e4;
      }
    }
    > input {
      width60px;
      padding0 5px;
      text-align: center;
      color#666;
    }
  }
}
</style>

“Vue封装数字框组件如何实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://blog.csdn.net/weixin_46862327/article/details/129349862

vue
AI

开发者交流群×