store组合式写法
count.ts组合式写法
import { reactive } from 'vue'
export const useLoveTalkStore = defineStore('talk', () => {
const talkList = reactive(
JSON.parse(localStorage.getItem('talkList') as string) || []
)
//getATalk函数相当于action
async function getATalk() {
//发请求,下面这行写法是:连续解构+重命名
let { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// //把请求回来的字符,包装成一个对象
let obj = { id: nanoid(), title } //简单写成title:content 上面let可以result改成 {data:{content}};还可以进一步 title {data:{content:title}}
// //放到数组中
talkList.unshift(obj)
}
//必须有return,不然无效
return { talkList, getATalk }
})
选项式写法
import { defineStore } from 'pinia'
import axios from 'axios'
import { nanoid } from 'nanoid'
export const useLoveTalkStore = defineStore('talk', {
actions: {
async getATalk() {
//发请求,下面这行写法是:连续解构+重命名
let { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// //把请求回来的字符,包装成一个对象
let obj = { id: nanoid(), title } //简单写成title:content 上面let可以result改成 {data:{content}};还可以进一步 title {data:{content:title}}
// //放到数组中
this.talkList.unshift(obj)
}
},
//state真正存储数据的地方
state() {
return {
talkList: JSON.parse(localStorage.getItem('talkList') as string) || []
// talkList: [
// { id: 'ftrfasdf01', title: '今天天气好' },
// { id: 'ftrfasdf02', title: '今天天气好2' },
// { id: 'ftrfasdf03', title: '今天天气好3' }
// ]
}
}
})
组件通信_方式1_props
- 父传子:属性值是非函数
<template>
<div class="father">
<h3>父组件</h3>
<h4>汽车:{{ car }}</h4>
<!-- 传递,子需要接收 -->
<Child :car="car" :sendToy="getToy"/>
</div>
</template>
子组件需要接收
<script setup lang="ts" name="Child">
import {ref} from 'vue'
// 数据
let toy = ref('奥特曼')
// 声明接收props
defineProps(['car','sendToy'])
</script>
- 子传父:属性值是函数
<template>
<div class="father">
<h3>父组件</h3>
<h4>汽车:{{ car }}</h4>
<!-- v-show、v-if条件渲染 不传递参数就不显示 -->
<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
<Child :car="car" :sendToy="getToy"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import {ref} from 'vue'
// 数据
let car = ref('奔驰')
let toy = ref('')
// 方法
function getToy(value:string){
toy.value = value
}
</script>
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{ toy }}</h4>
<h4>父给的车:{{ car }}</h4>
<button @click="sendToy(toy)">把玩具给父亲</button>
</div>
</template>
<script setup lang="ts" name="Child">
import {ref} from 'vue'
// 数据
let toy = ref('奥特曼')
// 声明接收props
defineProps(['car','sendToy'])
</script>
组件通信_方式2__自定义事件
<template>
<div class="father">
<h3>父组件</h3>
<h4>{{ str }}</h4>
<button @click="test">点我</button>
<!-- 给子组件Child绑定事件 -->
<Child/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
// 数据
let str = ref('你好')
function test() {
str.value = '哈哈'
}
</script>
可以简化写法
<template>
<div class="father">
<h3>父组件</h3>
<h4>{{ str }}</h4>
<button @click="str = '哈哈'">点我</button>
<!-- 给子组件Child绑定事件 -->
<Child/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
// 数据
let str = ref('你好')
</script>
$seven 特殊占位符 这是一个事件对象
<template>
<div class="father">
<h3>父组件</h3>
<h4>{{ str }}</h4>
<button @click="str = $event">点我</button>
<!-- 给子组件Child绑定事件 -->
<Child/>
</div>
</template>
子传父
<template>
<div class="father">
<h3>父组件</h3>
<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
<!-- 给子组件Child绑定事件 -->
<Child @send-toy="saveToy"/>
</div>
</template>
<Child @send-toy=“saveToy”/>
给组件绑定send-toy事件,只要这个事件被触发,saveToy就会被调用
如何触发事件
需要在子组件里面声明,用一个宏函数,defineEmits
还需要加上emit。这个可以放在任何想要触发的地方
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{ toy }}</h4>
<button @click="emit('send-toy',toy)">测试</button>
</div>
</template>
<script setup lang="ts" name="Child">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
// 声明事件
const emit = defineEmits(['send-toy'])
// onMounted(() => {
// setTimeout(() => {
// emit('send-toy')
// }, 3000);
// })
</script>
案例
父组件
<template>
<div class="father">
<h3>父组件</h3>
<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
<!-- 给子组件Child绑定事件 -->
<Child @send-toy="saveToy"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
// 数据
let toy = ref('')
// 用于保存传递过来的玩具
function saveToy(value:string){
console.log('saveToy',value)
toy.value = value
}
</script>
子组件
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{ toy }}</h4>
<button @click="emit('send-toy',toy)">测试</button>
</div>
</template>
<script setup lang="ts" name="Child">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
// 声明事件
const emit = defineEmits(['send-toy'])
</script>
组件通信_方式3__mitt
pubsub
$bus
mitt
接收数据:提前绑定好事件(提前订阅事件)
提供数据:在合适的时候触发事件(发布消息)
案例
哥哥传递玩具给弟弟
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具:{{ toy }}</h4>
<button @click="emitter.emit('send-toy',toy)">玩具给弟弟</button>
</div>
</template>
<script setup lang="ts" name="Child1">
import {ref} from 'vue'
import emitter from '@/utils/emitter';
// 数据
let toy = ref('奥特曼')
</script>
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>电脑:{{ computer }}</h4>
<h4>哥哥给的玩具:{{ toy }}</h4>
</div>
</template>
<script setup lang="ts" name="Child2">
import {ref,onUnmounted} from 'vue'
import emitter from '@/utils/emitter';
// 数据
let computer = ref('联想')
let toy = ref('')
// 给emitter绑定send-toy事件
emitter.on('send-toy',(value:any)=>{
toy.value = value
})
// 在组件卸载时解绑send-toy事件;对内存友好
onUnmounted(()=>{
emitter.off('send-toy')
})
</script>
组件通信_方式4__v-model
双向绑定
v-model用在html标签上
<template>
<div class="father">
<h3>父组件</h3>
<!-- v-model用在html标签上 -->
<!-- <input type="text" v-model="username"> -->
<!-- :value数据来到页面,@input页面来到数据 -->
<input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value">
</div>
</template>
v-model用在组件标签上
father.Vue
<template>
<div class="father">
<h3>父组件</h3>
<!-- v-model用在组件标签上 -->
<AtguiguInput v-model="username"/>
<!-- <AtguiguInput
:modelValue="username"
@update:modelValue="username = $event"
/> -->
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue";
import AtguiguInput from './AtguiguInput.vue'
// 数据
let username = ref('zhansgan')
</script>
<template>
<input
type="text"
:value="modelValue"
@input="emit('update:modelValue',(<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="AtguiguInput">
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue')
</script>
$event到底是什么,什么时候可以用.target
对于原生事件,$event就是事件对象——能.target
对于自定义事件,$event就是触发事件时,所传递的数据——不能.target
组件通信_v-model的细节
update:modelValue名称太长 可以更改名字
如果value可以更换,可以再组件标签上多次使用v-model
<template>
<div class="father">
<h3>父组件</h3>
<h4>{{ username }}</h4>
<h4>{{ password }}</h4>
<!-- 修改modelValue -->
<AtguiguInput v-model:ming="username" v-model:mima="password"/>
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue";
import AtguiguInput from './AtguiguInput.vue'
// 数据
let username = ref('zhansgan')
let password = ref('123456')
</script>
组件
<template>
<input
type="text"
:value="ming"
@input="emit('update:ming',(<HTMLInputElement>$event.target).value)"
>
<br>
<input
type="text"
:value="mima"
@input="emit('update:mima',(<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="AtguiguInput">
defineProps(['ming','mima'])
const emit = defineEmits(['update:ming','update:mima'])
</script>
组件通信_方式5__$attrs
概念:$attrs用于实现当前组件的父组件,向当前组件的子组件的通信(祖—孙)
祖-孙
father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>a:{{a}}</h4>
<h4>b:{{b}}</h4>
<h4>c:{{c}}</h4>
<h4>d:{{d}}</h4>
<Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" />
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import {ref} from 'vue'
let a = ref(1)
let b = ref(2)
let c = ref(3)
let d = ref(4)
</script>
child.vue 把祖所有值都传递给孙
<template>
<div class="child">
<h3>子组件</h3>
<!-- <h4>a:{{ a }}</h4>
<h4>其他:{{ $attrs }}</h4> -->
<GrandChild v-bind="$attrs"/>
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue'
// defineProps(['a'])
</script>
grandchild.vue
<template>
<div class="grand-child">
<h3>孙组件</h3>
<h4>a:{{ a }}</h4>
<h4>b:{{ b }}</h4>
<h4>c:{{ c }}</h4>
<h4>d:{{ d }}</h4>
<h4>x:{{ x }}</h4>
<h4>y:{{ y }}</h4>
</div>
</template>
<script setup lang="ts" name="GrandChild">
defineProps(['a','b','c','d','x','y'])
</script>
孙-组
father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>a:{{a}}</h4>
<Child :a="a" :updateA="updateA"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import {ref} from 'vue'
let a = ref(1)
function updateA(value:number){
a.value += value
}
</script>
grandchild.vue
<template>
<div class="grand-child">
<h3>孙组件</h3>
<h4>a:{{ a }}</h4>
<button @click="updateA(6)">点我将爷爷那的a更新</button>
</div>
</template>
<script setup lang="ts" name="GrandChild">
defineProps(['a','updateA'])
</script>
组件通信_方式6__ r e f s 与 refs与 refs与parent
father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>房产:{{ house }}</h4>
<button @click="changeToy">修改Child1的玩具</button>
<button @click="changeComputer">修改Child2的电脑</button>
<button @click="getAllChild($refs)">让所有孩子的书变多</button>
<Child1 ref="c1"/>
<Child2 ref="c2"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import { ref,reactive } from "vue";
let c1 = ref()
let c2 = ref()
// 数据
let house = ref(4)
// 方法
function changeToy(){
c1.value.toy = '小猪佩奇'
}
function changeComputer(){
c2.value.computer = '华为'
}
function getAllChild(refs:{[key:string]:any}){
console.log(refs)
for (let key in refs){
refs[key].book += 3
}
}
// 向外部提供数据
defineExpose({house})
</script>
child1.vue
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具:{{ toy }}</h4>
<h4>书籍:{{ book }} 本</h4>
<button @click="minusHouse($parent)">干掉父亲的一套房产</button>
</div>
</template>
<script setup lang="ts" name="Child1">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
let book = ref(3)
// 方法
function minusHouse(parent:any){
parent.house -= 1
}
// 把数据交给外部
defineExpose({toy,book})
</script>
child2.vue
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>电脑:{{ computer }}</h4>
<h4>书籍:{{ book }} 本</h4>
</div>
</template>
<script setup lang="ts" name="Child2">
import { ref } from "vue";
// 数据
let computer = ref('联想')
let book = ref(6)
// 把数据交给外部
defineExpose({computer,book})
</script>
$refs 父传子
父得到子数据
<template>
<div class="father">
<h3>父组件</h3>
<h4>房产:{{ house }}</h4>
<button @click="changeToy">修改Child1的玩具</button>
<button @click="getAllChild($refs)">让所有孩子的书变多</button>
<Child1 ref="c1"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import { ref,reactive } from "vue";
let c1 = ref()
// 数据
let house = ref(4)
// 方法
function changeToy(){
c1.value.toy = '小猪佩奇'
}
function getAllChild(refs:{[key:string]:any}){
for (let key in refs){
refs[key].book += 3
}
}
</script>
子必须把数据传递出去
<script setup lang="ts" name="Child1">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
let book = ref(3)
// 把数据交给外部
defineExpose({toy,book})
</script>
$parent 子传父
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具:{{ toy }}</h4>
<h4>书籍:{{ book }} 本</h4>
<button @click="minusHouse($parent)">干掉父亲的一套房产</button>
</div>
</template>
<script setup lang="ts" name="Child1">
import { ref } from "vue";
// 数据
let toy = ref('奥特曼')
let book = ref(3)
// 方法
function minusHouse(parent:any){
parent.house -= 1
}
</script>
说明 | 属性 |
---|---|
$refs | 值为对象,包含所有被ref属性标识的DOM元素或组件实例 |
$parent | 值为对象,当前组件的父组件实例对象 |
一个注意点
<script setup lang="ts" name="Father">
// 注意点:当访问obj.c的时候,底层会自动读取value属性,因为c是在obj这个响应式对象中的
let obj = reactive({
a:1,
b:2,
c:ref(3)
})
let x = ref(4)
console.log(obj.a)
console.log(obj.b)
console.log(obj.c) //自动拆包解包
console.log(x) //这不是4
</script>
组件通信_方式7__provide_inject
如何不打扰儿子,直接传递给孙 区别attrs
father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>银子:{{ money }}万元</h4>
<h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4>
<Child/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import {ref,reactive,provide} from 'vue'
let money = ref(100)
let car = reactive({
brand:'奔驰',
price:100
})
function updateMoney(value:number){
money.value -= value
}
// 向后代提供数据 不能是money.value 否则传递的就是个数字 无法改变
provide('moneyContext',{money,updateMoney})
provide('car',car)
</script>
GrandChild.vue
<template>
<div class="grand-child">
<h3>我是孙组件</h3>
<h4>银子:{{ money }}</h4>
<h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4>
<button @click="updateMoney(6)">花爷爷的钱</button>
</div>
</template>
<script setup lang="ts" name="GrandChild">
import { inject } from "vue";
let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(param:number)=>{}})
let car = inject('car',{brand:'未知',price:0})
</script>