Vue2和Vue3的emit、props、watch等知识点对比

1.props/defineProps
使用场景:

       一般当父组件需要给子组件传值的时候会用到。

        Vue2:props

vue2在父组件里引入子组件以后需要在components里面注册后再使用;

父组件
<son-compnents :info=info></son-components>

import SonCompnents from "./cpmponents/SonCompnents.vue"
  components: {
    SonCompnents,
  },
  data(){
     return {
      info:'个人信息'
        }
  }
子组件
props:['info'] //数组写法
props:{
 info:Stirng  //对象写法
}
Vue3:defineProps

vue3的父组件引用后直接使用即可;

父组件
<son-compnents :info=info></son-components>

import SonCompnents from "./cpmponents/SonCompnents.vue"
import {ref }from 'vue'
let info = ref('props传参')
子组件
<script setup>
import {ref,computed} from 'vue'
可以直接在template使用info 
对象写法,限制接收的类型
const props = defineProps({
  info:String
})

数组写法,不限制接收的类型
接收参数并保存
let x  = defineProps(['info','xxxx'])
console.log(x.info) 获取数据
</script>
Vue3:ts版本的defineProps
父组件:

<son :list="list"></son>

let list = [
   {name:'im',age:18}
]

子组件:

index.ts:

export interface Person{
  name:string,
  age:number,
 
}

ts接收参数并且限制类型,只接收名为list且类型为Person的参数
import {withDefaults,defineProps} from 'vue' 可有可无
defineProps<{list:Person}>()

ts设置只接收list参数 + 限制类型 + 限制必要性 +指定默认值
PS:withDefaults和defineProps属于宏函数可以不引入直接使用即可;
import {withDefaults,defineProps} from 'vue'
withDefaults(defineProps<{list?:Person}>(),{
list:()=>[{name:'a',age:15}]
})

withDefaults第一个参数为defineProps,第二个参数为一个对象,对象的属性值是返回函数来设置默认值,问号代表设置可传可不传。 
2. emit/defineEmits
使用场景:

用于子组件向父组件传递信息,修改父组件传的props的值

Vue2:emit
子组件
<button @click="sendMes(name)">点击向父组件传值</button>

data(){
   return{
    name:'子组件'
  }
 }

methods:{
   sendMes(name){
     this.$emit('getMes',name)   触发父组件绑定的getMes事件从而触发对应的方法,后面是传的参数

    }
}
父组件

<son-componet @getMes="changeMes"></son-componet>

import SonComponet from '@/components/SonComponet'

data(){
   return(){
      name:'原本的值'
    }
  }

methods:{
  changeMes(name){
   this.name=name
   }

}
Vue3:defineEmits
子组件
<el-button @click="sendMes">子组件给父组件传值</el-button>

defineEmits属于宏函数可以不从vue引用
const emits = defineEmits(["close"]);
const sendMes = ()=>{
   emits("close","传的参数") //可传可不传
}
父组件

<son-component @close= "changeMes"></son-component>

import SonComponent from '@/components/SonComponent.vue'
import {ref} from 'vue'

let mes = ref('原值')
const changeMes = (name)=>{
   mes.value = name 
  
}
3.watch
使用场景:

用于对数据的监听并实时做出处理;

Vue2:watch
子组件
1.监听对象的一个属性值并实时修改另一个值
    watch: {
        'form.currency': {
            handler(newValue, oldValue) {
                if (newValue == 'USD') {
                    this.currencyType = '万美元';
                } else {
                    this.currencyType = '万元';
                }
            },
            deep: true,

        },
        'form2.currency': {
            handler(newValue, oldValue) {
                if (newValue == 'USD') {
                    this.currencyType = '万美元';
                } else {
                    this.currencyType = '万元';
                }
            },
            deep: true
        }
    },
Vue3:watch

这里的场景是子组件是弹窗,父组件是表格,在表格中引入,点击编辑,子组件弹出框的数据随之更改;

子组件
import {ref,watch} from 'vue'

const props = defineProps({
   info:Obeject
})
let info = ref({})

当监听的值是一个对象的某个属性值时,watch的第一个参数就需要写成函数,其他直接写参数即可 
watch(
  ()=>props.info   //如果只是子组件本身的一个值 name,
  (newValue,oldValue)=>{
     if(newValue){
       form = {
         name = newValue.name
         price= newValue.price

      }
    } 
 },
  {     第三个对象配置watch的属性
  deep:true
  
  }
)

 如果监听的是对象里面的对象最好写成函数与deep:ture

let obj = reactive({

   a:1,

   smallObj:{

      c:1,

      d:4    

})

1.因为如果直接写obj.smallObj 不能监听整体的替换

watch(obj.smallObj,(newVal,oldVal)=>{

      如果触发语句是 obj.smallObj.c =2  能被监听到

     如果触发语句是 obj.smallObj = {  c:2, d:5 }  不能被监听到  地址变了

 })

2.如果直接写函数式obj.smallObj 不能监听到smallObj里面的属性变化

  watch(()=>obj.smallObj,(newVal,oldVal)=>{

      如果触发语句是 obj.smallObj.c =2  不能被监听到

     如果触发语句是 obj.smallObj = {  c:2, d:5 }  能被监听到  地址变了

}) 所以需要加上第三个deep的属性

Vue3:watchEffect 

 watchEffect的作用是不需要指定需要监听的属性,而是监听一个回调,当回调内所使用的数据发生变化时,回调就会执行;

缺点:1.不会立刻执行(可用immediate)解决;2.获取不到newValue和oldValue;

更多知识点得参考其他教程

import {watchEffect,ref} from 'vue'
let a = ref(1)
let b = ref(1)

const stop  =watchEffect(()=>{
  
  console.log(a,b) 一但a或b的值发生了改变,这个打印函数就会执行 
 
})
 Vue3:停止监听 

Vue3 的 watch可以返回一个函数,即 stopWatch。stopWatch 函数可以用来停止 watch监听器 

const stop = watch(count, (newVal, oldVal) => {
   if(newVal>10){
   stop()停止监听
  }
});

4. toRefs和toRef
Vue3:
类似于解构赋值,但是使用toRefs,对象里面的属性解构赋值出来也是响应式

let person={name:'im',age:12}

这样解构出来,就算改变了name和age的值,页面上也不会发生变化
let {name,age } = person  

这样解构出来,改变了name和age的值,页面上会发生变化
let {name,age } = toRefs(person)  

toRef就是指定对象里面的一个属性变成响应式

let {name } = toRef(person,'name')



数组也可以解构赋值

   let val = 'li-si'
   let arr = val.split('-')
   let [arr1, arr2] = arr
   firstName.value = arr1
   lastName.value = arr2
5.computed 
Vue3:

计算属性:有缓存

常规写法:

import {  computed } from 'vue'

let fullName = computed(()=>{

})

get与set的写法:当我们直接用函数改成一个computed得出来的属性的值,如通过函数调用直接写为fullName.value = 'li-si' ;

let fullName = computed(

   get(){

      retu return firstName.value.slice(0, 1).toUpperCase() + lastName.value

  },

  set(val){

        val可以获取到改变后赋的新值,只是获取,要自定义去赋值;

        let arr = val.split('-')

        let [arr1, arr2] = arr

        firstName.value = arr1

        lastName.value = arr2

   }

)

当使用set函数后,页面响应式改变,不用get,set会报错不允许修改只读的computed属性的值。

6.ref 和 defineExpose
Vue2:直接使用ref
<input ref="myInput">

使用: this.$refs.myInput  获取元素

Vue3:引入再使用
<input ref="title"></input>

<script setup lang="ts">
import { ref } from "vue";
 
let title = ref() 然后再使用
</script>
 defineExpose
如果父组件想调用子组件的数据

父组件
<son ref="son"></son>

子组件
import {defineExpose} from 'vue'
let a = ref(0)

defineExpose({a}) 此时父组件那边才能看到子组件的a,否则看不到什么。
7.ts自定义类型和接口
Vue3:定义对象
index.ts

定义对象接口
export interface person { 
    name: string,  这里必须小写且不带引号
    age: number,

}


ts.vue

必须加type
import { type person } from '@/type'
let person: person = {
    name: '张三',
    age: 18,
}


Vue3:自定义泛型
在上文的基础上,我想定义一个数组对象里面的对象类型为person

写法一:
let personList: Array<person> = [
    {
        name: '张三',
        age: 18,
    },
    {
        name: '张三',
        age: 18,
    }
]

写法二:
index.ts:

export type personList = person[];

ts.vue:

import { type personList } from '@/type'
let personList: personList = [
    {
        name: '张三',
        age: 18,
    },
    {
        name: '张三',
        age: 18,
    }
]

写法三:
index.ts:

export type personList = Array<person>;
 VUe3:响应式写类型以及可选属性
import { type PersonList} from "@/type"

let personList = reactvie<PersonList>([

{
  name:'张三',
  age:10
},
{
  name:'张三',
  age:10,
  heght:111
},
])


incdex.ts

我想在数组的最后一个对象有height属性 
在接口定义写成可选属性,即在属性后面加个问号
export interface person {
name:string,
age:number,
height?:number

}

export type PersonList = Array<person>
8.hooks
vue3:类似于Vue2的minxin
dog.js
hooks里面可以使用生命周期和钩子等等

import {reactive} from 'vue';
import axios from 'axios';

export default function(){
  
   //数据
   let dog  = reactive([])

   //方法
   async function getDog(){
     try{
        let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
        dog.push(result.data.message)

     }
     catch(err){
        consloe.log(err)
      }

  }
 
  //钩子
  onMounted(()=>getDog())

  //返回数据
  return { dog,getDog }
 
}
页面引入hooks
组件引用hooks

<template>
    <div>
        <img v-for="item in dog" :src="item" :key="item" alt="">
        <button @click="getDog">再来一只狗</button>
    </div>
</template>
<script setup>
import useDog from '@/hooks/dog.js'
const { dog, getDog } = useDog()  解构赋值后直接使用 引用后得调用
</script> 
<style scoped></style>
9.引入自定义组件
Vue2:

<Person ></Person>

import Person from './components/Person.vue'

export default{

       name: 'App', //组件的名字

       components:{Person} //注册组件

     }

Vue3:

 <Person ></Person>

引入后直接在template里面使用就可以;

PS:引入组件名得大写;

import Person from './components/Person.vue'

10.路由的props
1.常见写法(prams)
传递参数

1.对象写法
<RouterLink :to="`/new/detail/${item.id}/${item.name}`"> </RouterLink>

2.to的对象写写法
<RouterLink :to="{
            name:'xiang',
            params:{
               id:1,
               name:'变量',
           }

}"
>

接收参数
<div> {{params.id}} </div>

import {useRoute} from 'vue-router'
import {toRefs} from 'vue'

const route = useRoute()
let {params}  = toRefs(route)
2.params的路由传参
router.js

{

name:'new',
path:'/news',
component:News,
children:[
   {
      name:'xiang',
      path:'detail/:id/:name?',
      component:Detail,
      重点!!! 加上这个属性以后,可以直接在子组件使用参数值了,但是只限制于params
      props:true


   }

 ]

}


Detail.vue

<div> {{id}} </div>

defineProps(['id','name'])


3.query的路由传参
router.js

{

name:'new',
path:'/news',
component:News,
children:[
   {
      name:'xiang',
      path:'detail/:id/:name?',
      component:Detail,
      函数写法,可以接受到router整个参数
      props(route){
       return route.query
     }
  
   }

 ]

}

使用同上直接使用即可
11.使用pinia
main.js

引入pinia

import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)


使用pinia

新建store文件夹在里面根据需求取名 示例叫count.js

import { defineStore} from 'pinia'
参数一是id名 二是一个对象里面是一个函数 
export  const useCountStore = defineStore( 'count',{
      state(){
        return{
        sum:6
        }
 
      }

} )




组件使用:
<div>{{countStore.sum}}</div>


import { useCountStore } from '@/store/count'
cosnt  countStore = useCountStore()

PS:此时的pinia的数据不用value也可以直接取出来

1.
console.log(countStore.sum)
2.
console.log(countStore.$state.sum)

同等场景下的ref的数据不用点value就可以取出来 因为reactive 和pinia已经自动处理了

let obj = reactive({
 a:1,
 b:2,
 c:ref(2)


})
修改pinia的值

1.使用actions

import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", {
    state: () => ({
        count: 0
    }),
    // 定义计算属性
    getters: {
        doubleCount: (state) => state.count * 2
    },
    // 定义修改state的方法
    actions: {
        increment() {
            this.count++;
        }
    }
})

组件使用

    <button @click="countStore.increment">加一</button>

2.直接修改

function add(){

  countStore.count +=1

}

3.$patch

function add(){
  countStore.$patch({
   count:2

  })

}
12.pinia函数式写法

pinia的toRefs是 storeToRefs 


import { defineStore} from 'pinia'
参数一是id名 二是一个对象里面是一个函数 
export  const useCountStore = defineStore( 'count',()=>{

   const list = []
   function add(){
   list = [1]
   }


}

return {list ,add}
} )
13.mitt 

引入mitt

import mitt from 'mitt'
const emitter = mitt()

//绑定事件
emitter.on('test', () => { 
    console.log('test1被调用了');
})

//触发事件
emitter.emit('test1')

//解绑事件
emitter.off('test')
//解绑全部
emitter.all.clear()

//暴露emiiter
export default emitter

任意组件使用

发送方     
   <span @click="sendToy">11111</span>

   import emitter from "@/util/mitt"
  
   function sendToy() {
    console.log('发送数据');
    emitter.emit('send', '我是玩具')
  }


接收方

   import emitter from "@/util/mitt"
   import { ref } from 'vue'
   let toy = ref('')
  // 给emitter绑定事件接收事件
   emitter.on('send', (value) => {
    console.log('接收到数据', value);
    toy.value = value                  PS:ref记得.value
    // 这个是value是触发时传过来的
})

//解绑事件
onUnmounted(()=>{
 
emitter.off('send-toy')
  
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值