组件上的v-model(数据传递),props验证,自定义事件,计算属性

发布于:2024-09-19 ⋅ 阅读:(155) ⋅ 点赞:(0)

一.props验证

在封装组件时对外界传递过来的props数据进行合法性校验,从而防止数据不合法问题。

1.基础类型检查

String,Number,Boolean,Array,Object,Date,Function,Symbol

2.多个可能的类型
3.必须项校验
4.属性默认值
5.自定义验证函数
<template>
  <div>父组件</div>
  <DemoSon :msg="msg" :title="title" type="abc"></DemoSon>
</template>
<script>
import DemoSon from './son.vue'
export default {
    name:'demo',
    components:{DemoSon},
    data(){
        return{
            msg:'111',
            title:'abc'
        }
    }
}
</script>

<template>
  <div>子组件</div>
  <p>{{ msg }}{{ title }}</p>
</template>
<script>
export default {
    name:'demo-son',
    props:{
        msg:{
            type:[Number,String],
            required:true,
            default:10
        },
        title:String,
        type:{
            validator(value){
                // true成功,false失败
                return ['success','warning','danger'].indexOf(value)!==-1
            }
        }
    }
}
</script>

二.计算属性computed

计算属性本质上是一个function函数,可以监听data中数据的变化,并return一个计算后的值,供组件渲染dom时使用。

计算属性会缓存计算的结果,只有在计算属性的依赖项发生变化时,才会重新计算。

计算属性只能当作普通数据项使用,不能当作方法调用(不能使用括号调用)。

<template>
    <div>
        <input type="text" v-model.number="num">
    </div>
    <div>{{ plus }}</div>
</template>
  <script>
  export default {
      name:'demo',
      data(){
          return{
              num:111
          }
      },
      computed:{
        plus(){
           return  this.num*2
        }
      }
  }
  </script>
<template>
  <div>
    <table border>
      <tr><td class="goodState">状态</td>
          <td class="goodId">#</td>
          <td class="goodName">名称</td>
          <td class="goodPrice">单价</td>
          <td class="goodNum">数量</td>
          <td class="goodTime">价格</td>
          <td class="goodAction">操作</td>
      </tr>
      <tr v-for="(item,index) in goods.data" :key="item.id">
          <td class="goodState">
              <input type="checkbox" v-model="item.state" :id="item.id">
              <label :for="item.id">{{item.state===true?"上架":"下架"}}</label>
          </td>
          <td class="goodId">{{index+1}}</td>
          <td class="goodName">{{item.name}}</td>
          <td class="goodNum">{{item.price}}</td>
          <td class="goodNum">{{item.num}}</td>
          <td class="goodTime">{{item.num*item.price}}</td>
          <td class="goodAction"><b @click="addFn(item.id,item.num)">+</b><b @click="minusFn(item.id,item.num)">-</b></td>
      </tr>
      <tr>
          <td>总数:{{ number }}</td>
          <td>总计:{{ total }}</td>
      </tr>
    </table>
  </div>
</template>
  <script setup>
import { ref,reactive, computed } from "vue"
const goods=reactive({data:[{
         id:'1',
         name:'苹果',
         state:true,
         price:2,
         num:0,
         time:'2020-11-03 11:00:00'
     },
     {
         id:'2',
         name:'梨',
         state:true,
         price:2,
         num:0,
         time:'2020-11-03 11:00:00'
     },
     {
         id:'3',
         name:'香蕉',
         state:true,
         price:2,
         num:0,
         time:'2020-11-03 11:00:00'
     }
    ]
})
const minusFn=(id,num)=>{
    if(num>0){
    for(let i=0;i<goods.data.length;i++){
        if(goods.data[i].id===id){
            goods.data[i].num= num-1
        }
    }
}
}
const addFn=(id,num)=>{
    for(let i=0;i<goods.data.length;i++){
        if(goods.data[i].id===id){
            goods.data[i].num= num+1
        }
    }
}
const number = computed(()=>{
    let n=0;
    goods.data.forEach((item)=>{
        if(item.state){
            n+=item.num
        }
    })
    return n;
})
const total = computed(()=>{
    let sum=0;
    goods.data.forEach((item)=>{
        if(item.state){
            sum+=item.num*item.price
        }
    })
    return sum;
})
  </script>
  <style scoped lang="scss">
  td{
    width: 200px;
    height: 40px;
  }
  b{
    margin-right: 20px;
  }
</style>

三.自定义事件

1.声明自定义事件
2.触发自定义事件
3.监听自定义事件
<template>
  <div class="card">
    {{ count }}
    <Son @changeCount="changeCount"></Son>
  </div>
</template>
<script >
import Son from './son.vue'
export default{
  name:'index',
  components: {
    Son
  },
  data(){
    return{
      count:0
    }
  },
  methods:{
    changeCount(str){
      this.count = str
    }
  }
}
</script>

<template>
  <button type="button" @click="clickFn">按钮</button>
</template>
<script>
export default{
  name:'son',
  emits:['changeCount'],
  methods:{
    clickFn(){
      this.$emit('changeCount',1)
    }
  }
}
</script>
<template>
  <div class="card">
    {{ count }}
    <Son @changeCount="changeCount"></Son>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import Son from './son.vue'
const count = ref(0)
const changeCount = (str)=>{
  count.value = str
}
</script>

<template>
  <button type="button" @click="clickFn">按钮</button>
</template>
<script setup>
const emit = defineEmits('changeCount')
const clickFn = () => {
  emit('changeCount',1)
}
</script>

四.组件上v-model

1.父传子

a.父组件通过v-bind属性绑定的形式,把数据传递给子组件

b.子组件中,通过props接受子组件传递过来的数据

<template>
  <div>父组件</div>
  <DemoSon :msg="msg"></DemoSon>
</template>
<script>
import DemoSon from './son.vue'
export default {
    name:'demo',
    components:{DemoSon},
    data(){
        return{
            msg:'111'
        }
    }
}
</script>

<template>
  <div>子组件</div>
  <p>{{ msg }}</p>
</template>
<script>
export default {
    name:'demo-son',
    props:{
        msg:{
            type:[Number,String],
            required:true,
            default:10
        }
    }
}
</script>
2.子传父

a.在v-bind指令前添加v-model指令

b.在子组件中声明emits自定义事件,格式为update:xxx

c.调用$emit()触发自定义事件,更新父组件中的数据

<template>
  <div class="card">
    {{ count }}
    <Son v-model:number="count"></Son>
  </div>
</template>
<script >
import Son from './son.vue'
export default{
  name:'index',
  components: {
    Son
  },
  data(){
    return{
      count:0
    }
  }
}
</script>

<template>
  {{ number }}
  <button type="button" @click="clickFn">按钮</button>
</template>
<script>
export default{
  name:'son',
  props:['number'],
  emits:['update:number'],
  methods:{
    clickFn(){
      this.$emit('update:number',this.number+1)
    }
  }
}
</script>


网站公告

今日签到

点亮在社区的每一天
去签到