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')
})