Vue3's v-model syntactic sugar

Vue2's v-model defaults to: value and @input
Vue3's v-model defaults to: modelValue and @update:modelValue

So if you want to support the use of v-model by encapsulating components, using v-model syntactic sugar is undoubtedly the best choice

The child component definition uses modelValue to receive the value passed by the parent component, and defines the event update:modelValue to notify the parent component to change something

Example use: encapsulating subcomponents Usage: cp-radio-btn

//子组件 cp-radio-btn

<script setup lang="ts">
// 通过v-model双向绑定实现计数器
const props = defineProps<{
  modelValue: number
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', count: number): void
}>()
const btnClick = () => {
  emit('update:modelValue', props.modelValue + 10)
}
</script>

<template>
  <div class="cp-radio-btn">
    计数器:{
   
   { modelValue }} <br />
    <button @click="btnClick">修改count</button>
    //<button @click="$emit('update:modelValue', modelValue + 2)">修改count</button>
  </div>
</template>

<style lang="scss" scoped></style>

parent component patient - use child component cp-radio-btn

Use modelValue to pass data to subcomponents, and define events notified by subcomponents @update:modelValue to do things

//父组件 patient

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const count = ref(0)

const updateCount = (num: number) => {
  count.value = num
}
</script>

<cp-radio-btn :modelValue="count" @update:modelValue="updateCount"></cp-radio-btn>
//<cp-radio-btn :modelValue="count" @update:modelValue="count = $event"></cp-radio-btn>

This completes the two-way binding of data;

Here, :modelValue="count" @update:modelValue="updateCount" can be abbreviated as v-model="count"

Can achieve the same effect as the above code 

<cp-radio-btn v-model="count"></cp-radio-btn>

The above article began to say that Vue3's v-model is parsed into: modelValue and @update:modelValue by default. Let me talk about it below. If you want to modify the default value and event, how to modify it?

For example: when changing the name of the value event here (here, use OtherName as an example)

After using v-model, you need to add: OtherName

<cp-radio-btn v-model:OtherName="count"></cp-radio-btn>
子组件的传值以及事件都需要改为自定义的名称

<script setup lang="ts">
// 通过v-model双向绑定实现计数器
const props = defineProps<{
  OtherName: number
}>()

const emit = defineEmits<{
  (e: 'update:OtherName', OtherName: number): void
}>()
const btnClick = () => {
  emit('update:OtherName', props.OtherName + 10)
}
</script>

<template>
  <div class="cp-radio-btn">
    计数器:{
   
   { OtherName }} <br />
    <button @click="btnClick">修改OtherName</button>
  </div>
</template>

<style lang="scss" scoped></style>

 Encapsulate a custom radio button component cp-radio-btn to meet the following requirements

 

Post code:

<script setup lang="ts">
defineProps<{
  options: { label: string; value: number | string }[]
  modelValue?: number | string
}>()
defineEmits<{
  (e: 'update:modelValue', value: number | string): void
}>()
</script>

<template>
  <div class="cp-radio-btn">
    <a
      class="item"
      href="javascript:;"
      v-for="item in options"
      :key="item.value"
      :class="{ active: modelValue == item.value }"
      @click="$emit('update:modelValue', item.value)"
      >{
   
   { item.label }}</a
    >
  </div>
</template>

<style lang="scss" scoped>
.cp-radio-btn {
  display: flex;
  flex-wrap: wrap;
  .item {
    height: 32px;
    min-width: 60px;
    line-height: 30px;
    padding: 0 14px;
    text-align: center;
    border: 1px solid var(--cp-bg);
    background-color: var(--cp-bg);
    margin-right: 10px;
    box-sizing: border-box;
    color: var(--cp-text2);
    margin-bottom: 10px;
    border-radius: 4px;
    transition: all 0.3s;
    &.active {
      border-color: var(--cp-primary);
      background-color: var(--cp-plain);
    }
  }
}
</style>

 Use components:

<cp-radio-btn :options="timeOptions" v-model="form.illnessTime" />

Use vant's van-action-sheet action panel component to encapsulate a payment component  cp-pay-sheet

cp-pay-sheet

<script setup lang="ts">
import { showToast, showLoadingToast } from 'vant'
import { ref } from 'vue'
import { getConsultOrderPayUrl } from '@/services/consult'

const props = defineProps<{
  orderId: string
  actualPayment: number
  onClose?: () => void
  show: boolean
}>()
const emit = defineEmits<{
  (e: 'update:show', val: boolean): void
}>()

const paymentMethod = ref<0 | 1>()

// 跳转支付
const pay = async () => {
  if (paymentMethod.value === undefined) return showToast('请选择支付方式')
  showLoadingToast({ message: '跳转支付', duration: 0 })
  const res = await getConsultOrderPayUrl({
    orderId: props.orderId,
    paymentMethod: paymentMethod.value,
    payCallback: 'http://localhost:5173/room'
  })
  window.location.href = res.data.payUrl
}
</script>

<template>
  <!-- 支付方式弹窗 -->
  <van-action-sheet
    :show="show"
    @update:show="emit('update:show', $event)"
    title="选择支付方式"
    :close-on-popstate="false"
    :closeable="false"
    :before-close="onClose"
  >
    <div class="pay-type">
      <p class="amount">¥20.00</p>
      <van-cell-group>
        <van-cell title="微信支付" @click="paymentMethod = 0">
          <template #icon><cp-icon name="consult-wechat" /></template>
          <template #extra><van-checkbox :checked="paymentMethod == 0" /></template>
        </van-cell>
        <van-cell title="支付宝支付" @click="paymentMethod = 1">
          <template #icon><cp-icon name="consult-alipay" /></template>
          <template #extra><van-checkbox :checked="paymentMethod == 1" /></template>
        </van-cell>
      </van-cell-group>
      <div class="btn">
        <van-button type="primary" round block @click="pay">立即支付</van-button>
      </div>
    </div>
  </van-action-sheet>
</template>

<style lang="scss" scoped>
.pay-type {
  .amount {
    padding: 20px;
    text-align: center;
    font-size: 16px;
    font-weight: bold;
  }
  .btn {
    padding: 15px;
  }
  .van-cell {
    align-items: center;
    .icon-page {
      margin-right: 10px;
      font-size: 18px;
      margin-top: 6px;
    }
    .van-checkbox :deep(.van-checkbox__icon) {
      font-size: 16px;
    }
  }
}
</style>

 use components

    <cp-pay-sheet

      v-model:show="show"

      :order-id="orderId"

      :actual-payment="payInfo.actualPayment"

      :on-close="onClose"

    ></cp-pay-sheet>

Guess you like

Origin blog.csdn.net/luoxiaonuan_hi/article/details/130523912