Vue封裝數(shù)字框組件實(shí)現(xiàn)流程詳解
數(shù)量選擇組件-基本結(jié)構(gòu)
(1)準(zhǔn)備基本結(jié)構(gòu)
<script lang="ts" setup name="Numbox">
//
</script>
<template>
<div class="numbox">
<div class="label">數(shù)量</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 {
width: 60px;
color: #999;
padding-left: 10px;
}
.numbox {
width: 120px;
height: 30px;
border: 1px solid #e4e4e4;
display: flex;
> a {
width: 29px;
line-height: 28px;
text-align: center;
background: #f8f8f8;
font-size: 16px;
color: #666;
&:first-of-type {
border-right: 1px solid #e4e4e4;
}
&:last-of-type {
border-left: 1px solid #e4e4e4;
}
}
> input {
width: 60px;
padding: 0 5px;
text-align: center;
color: #666;
}
}
}
</style>
(2)全局注冊(cè)
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 {
Numbox: typeof Numbox
}
}
export {}
(4)渲染
<div class="spec"> <!-- 數(shù)字選擇框 --> <XtxNumbox></XtxNumbox> </div>
效果

數(shù)量選擇組件-v-model語(yǔ)法糖
目標(biāo):掌握vue3.0的v-model語(yǔ)法糖原理
在vue2.0中v-mode語(yǔ)法糖簡(jiǎn)寫的代碼 <Son :value="msg" @input="msg=$event" />
在vue3.0中v-model語(yǔ)法糖有所調(diào)整:<Son :modelValue="msg" @update:modelValue="msg=$event" />
演示代碼:
<script lang="ts" setup>
defineProps({
money: {
type: Number,
default: 0,
},
})
const emit = defineEmits(['update:money'])
</script>
<template>
<h3>子組件-{{ money }}</h3>
<button @click="emit('update:money', money + 1)">+1</button>
</template>
<style scoped lang="less"></style>
總結(jié): vue3.0封裝組件支持v-model的時(shí)候,父?jìng)髯?code>:modelValue 子傳父 @update:modelValue
補(bǔ)充: vue2.0的 xxx.sync 語(yǔ)法糖解析 父?jìng)髯?:xxx 子傳父 @update:xxx 在vue3.0 使用 v-model:xxx 代替。
數(shù)量選擇組件-功能實(shí)現(xiàn)
大致功能分析:
- 默認(rèn)值為1
- 可限制最大最小值
- 點(diǎn)擊-就是減1 點(diǎn)擊+就是加1
- 需要完成v-model得實(shí)現(xiàn)
- 存在無(wú)label情況
<script lang="ts" setup name="Numbox">
const props = defineProps({
modelValue: {
type: Number,
default: 1,
},
min: {
type: Number,
default: 1,
},
max: {
type: Number,
default: 20,
},
showLabel: {
type: Boolean,
default: false,
},
})
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const add = () => {
if (props.modelValue >= props.max) return
emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
if (props.modelValue <= props.min) return
emit('update:modelValue', props.modelValue - 1)
}
</script>
<template>
<div class="numbox">
<div class="label" v-if="showLabel"><slot>數(shù)量</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 {
width: 60px;
color: #999;
padding-left: 10px;
}
.numbox {
width: 120px;
height: 30px;
border: 1px solid #e4e4e4;
display: flex;
> a {
width: 29px;
line-height: 28px;
text-align: center;
background: #f8f8f8;
font-size: 16px;
color: #666;
&:first-of-type {
border-right: 1px solid #e4e4e4;
}
&:last-of-type {
border-left: 1px solid #e4e4e4;
}
}
> input {
width: 60px;
padding: 0 5px;
text-align: center;
color: #666;
}
}
}
</style>
動(dòng)態(tài)控制禁用效果
<script lang="ts" setup name="Numbox">
const props = defineProps({
modelValue: {
type: Number,
default: 1,
},
min: {
type: Number,
default: 1,
},
max: {
type: Number,
default: 20,
},
showLabel: {
type: Boolean,
default: false,
},
})
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const add = () => {
if (props.modelValue >= props.max) return
emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
if (props.modelValue <= props.min) return
emit('update:modelValue', props.modelValue - 1)
}
</script>
<template>
<div class="numbox">
<div class="label" v-if="showLabel"><slot>數(shù)量</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 {
width: 60px;
color: #999;
padding-left: 10px;
}
.numbox {
width: 120px;
height: 30px;
border: 1px solid #e4e4e4;
display: flex;
> a {
width: 29px;
line-height: 28px;
text-align: center;
background: #f8f8f8;
font-size: 16px;
color: #666;
+ &.not {
+ cursor: not-allowed;
+ }
&:first-of-type {
border-right: 1px solid #e4e4e4;
}
&:last-of-type {
border-left: 1px solid #e4e4e4;
}
}
> input {
width: 60px;
padding: 0 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">
<!-- 數(shù)字選擇框 -->
<XtxNumbox v-model="count" min:"1" :max="20" ></XtxNumbox>
</div>
思考:
我們的輸入框不僅能點(diǎn)擊加減還可以輸入數(shù)字,如果用戶通過(guò)輸入框輸入非數(shù)字會(huì)出現(xiàn)什么問(wèn)題?

優(yōu)化代碼
<script lang="ts" setup name="Numbox">
const props = defineProps({
modelValue: {
type: Number,
default: 1,
},
min: {
type: Number,
default: 1,
},
max: {
type: Number,
default: 20,
},
showLabel: {
type: Boolean,
default: false,
},
})
+const { proxy } = getCurrentInstance() as ComponentInternalInstance
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const add = () => {
if (props.modelValue >= props.max) return
emit('update:modelValue', props.modelValue + 1)
}
const sub = () => {
if (props.modelValue <= props.min) return
emit('update:modelValue', props.modelValue - 1)
}
+const handleChange = (e: Event) => {
+ // 通過(guò)類型斷言,讓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)
+ // 強(qiáng)制刷新
+ proxy?.$forceUpdate()
}
</script>
<template>
<div class="numbox">
<div class="label" v-if="showLabel"><slot>數(shù)量</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 {
width: 60px;
color: #999;
padding-left: 10px;
}
.numbox {
width: 120px;
height: 30px;
border: 1px solid #e4e4e4;
display: flex;
> a {
width: 29px;
line-height: 28px;
text-align: center;
background: #f8f8f8;
font-size: 16px;
color: #666;
&.not {
cursor: not-allowed;
}
&:first-of-type {
border-right: 1px solid #e4e4e4;
}
&:last-of-type {
border-left: 1px solid #e4e4e4;
}
}
> input {
width: 60px;
padding: 0 5px;
text-align: center;
color: #666;
}
}
}
</style>
到此這篇關(guān)于Vue封裝數(shù)字框組件實(shí)現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)Vue封裝數(shù)字框組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Vue中實(shí)現(xiàn)對(duì)文件的壓縮和解壓縮功能
在前端開(kāi)發(fā)中,文件的壓縮和解壓縮是經(jīng)常需要用到的功能,尤其是在需要上傳和下載文件的場(chǎng)景下,文件壓縮可以減小文件大小,加快文件傳輸速度,提高用戶體驗(yàn),本文將介紹在Vue項(xiàng)目中如何進(jìn)行文件的壓縮和解壓縮,需要的朋友可以參考下2023-11-11
Nuxt.js之自動(dòng)路由原理的實(shí)現(xiàn)方法
這篇文章主要介紹了Nuxt.js之自動(dòng)路由原理的實(shí)現(xiàn)方法,nuxt.js會(huì)根據(jù)pages目錄結(jié)構(gòu)自動(dòng)生成vue-router模塊的路由配置。非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-11-11
vue中使用loadsh的debounce防抖函數(shù)問(wèn)題
這篇文章主要介紹了vue中使用loadsh的debounce防抖函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
關(guān)于vue-cli 3配置打包優(yōu)化要點(diǎn)(推薦)
這篇文章主要介紹了vue-cli 3配置打包優(yōu)化要點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
vue新建項(xiàng)目并配置標(biāo)準(zhǔn)路由過(guò)程解析
這篇文章主要介紹了vue新建項(xiàng)目并配置標(biāo)準(zhǔn)路由過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
使用vue實(shí)現(xiàn)滑動(dòng)滾動(dòng)條來(lái)加載數(shù)據(jù)
在vuejs中,我們經(jīng)常使用axios來(lái)請(qǐng)求數(shù)據(jù),但是有時(shí)候,我們請(qǐng)求的數(shù)據(jù)量很大,那么我們?nèi)绾螌?shí)現(xiàn)滑動(dòng)滾動(dòng)條來(lái)加載數(shù)據(jù)呢,接下來(lái)小編就給大家介紹一下在vuejs中如何實(shí)現(xiàn)滑動(dòng)滾動(dòng)條來(lái)動(dòng)態(tài)加載數(shù)據(jù),需要的朋友可以參考下2023-10-10
簡(jiǎn)單實(shí)現(xiàn)一個(gè)vue公式編輯器組件demo
這篇文章主要介紹了輕松實(shí)現(xiàn)一個(gè)簡(jiǎn)單的vue公式編輯器組件示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01

