结合目录,点击阅读
文章目录
- 案例1:第一行vue代码
-
- App.vue引入Person.vue
- 案例:改变变量的值
- 案例:改变对象属性值
- 案例:toRefs进行解包
- 案例:给名字首字母大写
- 案例:监视变量值的变化
- 案例:监视对象属性值的变化
- 案例:监视reactive对象属性值的变化
- 案例:监视reactive对象定义的某个属性值
- 案例:监视reactive对象定义的多个属性值
- 案例:watchEffect监视ref变量的值
- 案例:defineExpose通信
- 案例:组件通信
- 案例:状态与钩子函数
- 案例:Component声明与使用
- 案例:创建路由器
- 案例:创建子路由
- 案例:路由传参
- 案例:路由props
- 案例:路由重定向
- 案例:store
- 案例:数据修改
- 案例:pina中storeToRefs
- 案例:pinia进行数据改变
- 案例:defineProps
- 案例:shallowRef
- 案例:readOnly与shallowReadOnly
- 案例:markRaw与toRaw
- 案例:customRef
- 案例:telePort
- 案例:fallback
- app相关的操作
- 案例:作用域插槽
- 案例:组件通信1
- 案例:组件通信2-customEvent
- 案例:组件通信3-mitt
- 案例:组件通信4
- 案例:组件通信5
- 案例:组件通信6
- 案例:组件通信7
- 案例:组件通信8
案例1:第一行vue代码

App.vue引入Person.vue

typescript
<template>
<div class="app">
<h1>你好啊!</h1>
<Person/>
</div>
</template>
<script lang="ts">
import Person from './Person.vue'
export default {
name: 'App',
components: {
Person
}
}
</script>
Person.vue
typescript
<template>
<div class="person">
<h2>姓名:{{a}}</h2>
</div>
</template>
<script lang="ts" setup name="Person5467">
let a = 666
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
案例:改变变量的值
typescript
const age = ref(18)
age.value = 21
案例:改变对象属性值
html遍历游戏列表
html
<ul>
<li v-for="g in games" :key="g.id">
{{g.name}}
</li>
</ul>
typescript
let car = reactive({brand:'奔驰',price:100})
let games = reactive([
{id:'001',name:'王者荣耀'},
{id:'002',name:'原神'},
{id:'003',name:'三国志'}
])
function changePrice() {
car.price += 10
console.log(car.price)
}
function changeFirstGame() {
games[0].name = "三国志123"
}
案例:toRefs进行解包
typescript
let person = reactive({
name:'张三',
age:18
})
//toRef与toRefs都是将响应式对象进行解包
let {name,age} = toRefs(person)
案例:给名字首字母大写
html
全名: <span>{{ fullname }}</span><br>
<button @click="changeFullName">将全名改</button>
ts代码
html
let fullname = computed({
get() {
return firstname.value.slice(0,1).toUpperCase() + firstname.value.slice(1) + "-" + lastname.value
},
set(val) {
const[str1,str2] = val.split('-')
firstname.value = str1
lastname.value = str2
}
})
案例:监视变量值的变化
typescript
let sum = ref(0)
function changeSum() {
sum.value += 1
}
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
})
案例:监视对象属性值的变化
typescript
let person = ref({
name:'张三',
age:18
})
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{deep:true})
案例:监视reactive对象属性值的变化
typescript
let person = reactive({
name:'张三',
age:18
})
let obj = reactive({
a :{
b:{
c:555
}
}
})
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
})
watch(obj,(newValue,oldValue)=>{
console.log('Obj变化了',newValue,oldValue)
})
案例:监视reactive对象定义的某个属性值
typescript
let person = reactive({
name:'张三',
age:31,
model:'汽车',
car:{
c1:'奔驰',
c2:'宝马'
}
})
watch(()=>person.name,(newValue,oldValue)=>{
console.log(newValue,oldValue)
})
案例:监视reactive对象定义的多个属性值
typescript
let person = reactive({
name:'张三',
age:31,
model:'汽车',
car:{
c1:'奔驰',
c2:'宝马'
}
})
watch(()=>person.name,(newValue,oldValue)=>{
console.log(newValue,oldValue)
})
watch([()=>person.name,()=>person.car.c1],(newValue,oldValue)=>{
console.log('person变化了',oldValue,newValue)
},{deep:true})
案例:watchEffect监视ref变量的值
typescript
let tempature = ref(0)
let height = ref(10)
watchEffect(()=>{
if(tempature.value > 20 || height.value > 30 ){
console.log("aa")
}
})
案例:defineExpose通信
typescript
<Person ref="ren"/>
typescript
<script lang="ts" setup name="App">
import {ref} from 'vue'
//ts或者js
import Person from './components/Person.vue'
let title2 = ref()
let ren = ref()
function showLog(){
console.log(ren.value)
}
</script>
typescript
<script lang="ts" setup name="Person5467">
import {ref,defineExpose} from 'vue'
let title2 = ref()
let a = ref(0)
let b = ref(0)
let c = ref(0)
function showLog() {
console.log("Person.Log")
}
defineExpose({a,b,c})
</script>
案例:组件通信
typescript
<script lang="ts" setup name="App">
import {reactive} from 'vue'
//ts或者js
let x = 4
import {type Persons} from '@/types'
import Person from './components/Person.vue'
let personList = reactive<Persons>([
{id:'001',name:'张三',age:13},
{id:'002',name:'李四',age:20},
{id:'003',name:'王五',age:22},
])
</script>
typescript
<script lang="ts" setup name="Person5467">
import type { Persons } from '@/types';
import { defineProps,withDefaults } from 'vue';
// 接收list
// defineProps(['list'])
//接收list+限制类型
// defineProps<{list:Persons}>()
//接收list+限制类型+限制必要性+指定默认值
withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'1',name:'张三',age:12}]
})
</script>
案例:状态与钩子函数
typescript
<script lang="ts" setup name="Person5467">
import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, ref } from 'vue';
let sum = ref(0)
function add(){
sum.value += 1
}
//挂载前
onBeforeMount(()=>{
console.log('挂载前')
})
//挂载后
onMounted(()=>{
console.log("已挂载")
})
//更新前
onBeforeUpdate(()=>{
console.log("更新前")
})
//更新完毕
onUpdated(()=>{
console.log("更新完毕")
})
//卸载前
onBeforeUnmount(()=>{
console.log("卸载前")
})
//卸载完毕
onUnmounted(()=>{
console.log("卸载完毕")
})
</script>
案例:Component声明与使用
ts文件
typescript
import { ref } from "vue"
export default function (){
let sum =ref(0)
function add(){
sum.value += 1
}
return {sum,add}
}
vue文件组件加载
typescript
<template>
<Person/>
</template>
<script lang="ts">
import Person from "./components/Person.vue"
export default {
name:'App',
components:{Person} //注册组件
}
</script>
vue文件:ts文件加载
typescript
<script lang="ts" setup name="Person5467">
import useDog from '@/hooks/useDog'
import useSum from '@/hooks/useSum'
const {sum,add} = useSum()
const {dogList,getDog} = useDog()
</script>
案例:创建路由器
typescript
import {createRouter, createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
//第二部:创建路由器
const router = createRouter({
history:createWebHistory(),
routes:[
{
path:'/home',
component:Home
},
{
path:'/about',
component:About
},
{
path:'/news',
component:News
},
]
})
export default router
typescript
<template>
<div class="app">
<h2 class="title">Vue路由测试</h2>
<div class="navigate">
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/news" active-class="active">新闻</RouterLink>
<RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
</div>
<div class="main-content">
<RouterView></RouterView>
</div>
</div>
</template>
案例:创建子路由
typescript
import {createRouter, createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
//第二部:创建路由器
const router = createRouter({
history:createWebHistory(),
routes:[
{
path:'/home',
component:Home
},
{
path:'/about',
component:About
},
{
path:'/news',
component:News,
children:[
{
path:'detail',
component:Detail
}
]
},
]
})
export default router
案例:路由传参
typescript
<RouterLink
:to = "{
name:'detail',
params:{
id:news.id,
title:news.title,
content:news.content,
}
}">{{ news.title }}</RouterLink>
案例:路由props
typescript
<script setup lang="ts" name="News">
import { useRoute } from 'vue-router';
defineProps(['id','title','content'])
</script>
案例:路由重定向
typescript
const router = createRouter({
history:createWebHistory(),
routes:[
{
path:'/home',
component:Home
},
{
path:'/about',
component:About
},
{
path:'/news',
component:News,
children:[
{
name:'detail',
path:'detail/:id/:title/:content',
component:Detail,
//第一种写法,将路由收到的所有params参数作为props传给路由组件
props:true,
//第二种写法:可以自己决定讲什么作为参数
// props(to) {
// console.log(to.query.id,to.query.title,to.query.content)
// return to.query
// },
}
]
},
{
path:'/',
redirect:'/home'
}
]
})
案例:store
ts文件
typescript
import { defineStore } from "pinia"
export const useCountStore = defineStore('count',{
state() {
return {
sum:6
}
}
})
typescript
<script setup lang="ts" name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count'
const countStore = useCountStore()
//reactive 里面包含ref,就不需要拆包value
console.log('@@@',countStore.sum)
let n = ref(1)
function add() {
}
function minus() {
}
</script>
案例:数据修改
typescript
<script setup lang="ts" name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count'
const countStore = useCountStore()
//reactive 里面包含ref,就不需要拆包value
console.log('@@@',countStore.sum)
let n = ref(1)
function add() {
// countStore.sum += 1
//第二种改变方式
// countStore.$patch({
// sum:888,
// school:'尚硅谷',
// address:'北京'
// })
//第三宗
countStore.increment(n.value)
}
</script>
typescript
import { defineStore } from "pinia"
export const useCountStore = defineStore('count',{
actions:{
increment(value: number){
console.log("increment被调用了",value)
this.sum += value
}
},
state() {
return {
sum:6,
school:'atguigu',
address:'hong'
}
}
})
案例:pina中storeToRefs
typescript
<script setup lang="ts" name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count'
import { storeToRefs } from 'pinia';
const countStore = useCountStore()
//reactive 里面包含ref,就不需要拆包value
console.log('@@@',countStore.sum)
let n = ref(1)
const {school,address,sum} = storeToRefs(countStore)
function add() {
countStore.increment(n.value)
}
</script>
typescript
import { defineStore } from "pinia"
export const useCountStore = defineStore('count',{
actions:{
increment(value: number){
console.log("increment被调用了",value)
this.sum += value
}
},
state() {
return {
sum:6,
school:'atguigu',
address:'hong'
}
}
})
案例:pinia进行数据改变
typescript
import { defineStore } from "pinia"
export const useCountStore = defineStore('count',{
actions:{
increment(value: number){
console.log("increment被调用了",value)
this.sum += value
}
},
state() {
return {
sum:6,
school:'atguigu',
address:'hong'
}
},
getters:{
bigSum:state =>state.sum * 10,
upperSchool():string{
return this.school.toUpperCase()
}
}
})
案例:defineProps
Father.vue
typescript
<template>
<div class="father">
<h3>父组件</h3>
<h4>父亲的玩具:{{ car }}</h4>
<h4>儿子的玩具:{{ 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(v:string){
toy.value = v
}
</script>
<style scoped>
.father {
background-color: rgb(165,164,164);
padding: 20px;
border-radius: 10px;
}
</style>
Child.vue
typescript
<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('奥特玛')
defineProps(['car','sendToy'])
function send() {
}
</script>
<style scoped>
.child {
background-color: skyblue;
padding:10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
</style>
案例:shallowRef
typescript
<template>
<div class="app">
<h3>求和为:{{ sum }}</h3>
<h3>名字为:{{ person.name }}</h3>
<h3>年龄为:{{ person.age }}</h3>
<h3>车子为{{car}}</h3>
<button @click="changeSum">sum+1</button>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
<span>|</span>
<button @click="changeBrand">修改品牌</button>
<button @click="changeColor">修改品牌</button>
<button @click="changeEngine">修改品牌</button>
</div>
</template>
<script lang="ts" setup name="App">
import {reactive, ref, shallowReactive, shallowRef} from 'vue'
//shallowRef只关心浅层次,也就是第一层**.value
//实战中更关心整体替换,下面是一串官方的话
//通过使用shallowRef()和shallowReactive()来绕开深度相应,
//浅层式api创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理
//避开了对每一个内部属性做响应式所带来的性能成本,这使得
//属性的访问变得更快,可提升性能
let sum = shallowRef(0)
let person = shallowRef({
name:'张三',
age:18
})
let car = shallowReactive({
brand:'帕拉梅拉',
options:{
engine:'v8',
color:'purple'
}
})
function changeSum(){
sum.value += 1
}
function changeName(){
person.value.name += '李四'
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value.age += 3
person.value.name += '王五'
}
function changeBrand(){
car.brand = "法拉利"
}
function changeColor(){
car.options.color = "blue"
}
function changeEngine(){
car.options.engine = "v12"
}
</script>
<style scoped>
.app{
background-color: #ddd;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 10px;
}
</style>
案例:readOnly与shallowReadOnly
typescript
<template>
<div class="app">
<h3>当前sum1为:{{ sum1 }}</h3>
<h3>当前sum2为:{{ sum2 }}</h3>
<h3>当前车为{{car1}}</h3>
<h3>当前车为{{car2}}</h3>
<button @click="changeSum1">点我sum1+1</button>
<button @click="changeSum2">点我sum2+1</button>
<button @click="changeBrand">修改品牌</button>
<button @click="changeColor">修改颜色</button>
<button @click="changePrice">修改价格</button>
</div>
</template>
<script lang="ts" setup name="App">
import {ref,readonly,reactive, shallowReadonly} from 'vue';
let sum1 = ref(0)
let sum2 = readonly(sum1) //深只读副本
let car1 = reactive({
brand:'奔驰',
options:{
color:'红色',
price:100
}
})
let car2 = shallowReadonly(car1) //只用于对象的顶层属性
function changeSum1(){
sum1.value += 1
}
function changeSum2() {
sum2.value += 1
}
function changeBrand() {
car2.brand = '帕拉梅拉'
}
function changeColor() {
car2.options.color = 'purple'
}
function changePrice() {
car2.options.price = 200
}
</script>
<style scoped>
.app{
background-color: #ddd;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 10px;
}
</style>
案例:markRaw与toRaw
typescript
<template>
<!-- toRaw:用于获取一个响应式对象的原始对象, -->
<!-- toRaw返回的对象不再是响应式的,不会触发视图更新 -->
<!-- markRow:标记一个对象,使其永远不会变成响应式的 -->
<h2>姓名:{{ person2.name }}</h2>
<h2>年龄:{{ person2.age }}</h2>
<h2>一个车子{{ car2 }}</h2>
<button @click="person2.age += 1">修改年龄</button>
<button @click="changePerson(person2)">修改整个人</button>
<button @click="car2.price += 10">修改车的价格</button>
</template>
<script lang="ts" setup name="App">
import {markRaw, reactive,toRaw} from 'vue'
let person2 = reactive({
name:'tony',
age:17
})
let rawPerson = toRaw(person2)
function changePerson(p){
p.age +=1
p.name = 'tom'
}
let car = markRaw({brand:'帕拉梅拉',price:100})
let car2 = reactive(car)
</script>
<style scoped>
.app{
background-color: #ddd;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 10px;
}
</style>
案例:customRef
自定义ref useMsg.ts
typescript
import { customRef } from 'vue';
export default function(initValue:string,delay:number){
let timer:number
let msg = customRef((track,trigger)=>{
return {
get() {
track()
return initValue
},
set(value){
clearTimeout(timer)
timer = setTimeout(()=>{
console.log('set',value)
initValue = value
trigger()
},delay)
}
}
})
return {msg}
}
.vue
typescript
<template>
<h3>我想要的:{{ msg }}</h3>
<input type="text" v-model="msg">
</template>
<script lang="ts" setup name="App">
import useMsg from './useMsg';
let {msg} = useMsg('你好',2000)
</script>
<style scoped>
.app{
background-color: #ddd;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 10px;
}
</style>
案例:telePort
Modal.vue
typescript
<template>
<button @click="isShow=true">暂时弹窗</button>
<div class="modal" v-show="isShow">
<h2>我是标题</h2>
<p>我是内容</p>
<button>我是弹窗</button>
</div>
<!-- 创建一个自定义的ref,并对其依赖项追踪和更新触发进行逻辑控制 -->
</template>
<script lang="ts" setup name="Modal">
import { ref } from 'vue';
let isShow = ref(false)
</script>
<style scoped>
.modal{
width: 200px;
height: 150px;
background-color: skyblue;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 5px;
text-align: center;
position: fixed;
left:50%;
top:20px;
margin-left: -100px;
}
</style>
App.vue
typescript
<template>
<div class="outer">
<h2>我是app组件</h2>
<img src="./tmp.png" alt="">
<br>
<Modal />
</div>
</template>
<script lang="ts" setup name="App">
import Modal from './Modal.vue'
</script>
<style scoped>
.outer {
background-color: #ddd;
border-radius: 10px;
padding: 5px;
box-shadow: 0 0 10px;
}
img {
width: 400px;
filter: saturate(280%);
}
</style>
案例:fallback
typescript
<template>
<div class="app">
<h2>我是app组件</h2>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h2>加载中....</h2>
</template>
</Suspense>
</div>
</template>
<script lang="ts" setup name="App">
import Child from './Child.vue'
import { Suspense } from 'vue';
</script>
<style scoped>
.app {
background-color: #add;
border-radius: 10px;
padding: 10px;
box-shadow: 0 0 10px;
}
</style>
typescript
<template>
<div class="child">
<img :src="message">
</div>
</template>
<script lang="ts" setup name="Child">
import {ref} from 'vue'
import axios from 'axios';
let sum = ref(0)
let {data:{message}} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
console.log(message)
</script>
<style scoped>
.child {
background-color: #bce;
border-radius: 10px;
padding: 10px;
box-shadow: 0 0 10px;
}
</style>
app相关的操作
main.ts
typescript
import {createApp} from 'vue'
import App from './App.vue'
import Hello from './Hello.vue'
const app = createApp(App)
app.component('Hello',Hello)
app.config.globalProperties.x = 99
declare module 'vue' {
interface ComponentCustomProperties {
x:number
}
}
app.directive('beauty',(element,{value})=>{
element.innerText += value
element.style.color = 'green'
element.style.backgroundColor = 'yellow'
})
app.mount('#app')
// setTimeout(()=>{
// app.unmount()
// },2000)
App.vue
typescript
<template>
<div class="app">
<h2>我是app组件</h2>
<Hello/>
<Child/>
</div>
</template>
<script lang="ts" setup name="App">
import Child from './Child.vue'
</script>
<style scoped>
.app {
background-color: #add;
border-radius: 10px;
padding: 10px;
box-shadow: 0 0 10px;
}
</style>
Child.vue
typescript
<template>
<div class="child">
<h2>我是child组件</h2>
<h3 >当前求和为:{{ sum }}</h3>
<h3 v-beauty="sum">差值</h3>
<Hello/>
</div>
</template>
<script lang="ts" setup name="Child">
import {ref} from 'vue'
let sum = ref(3)
</script>
<style scoped>
.child {
background-color: #bce;
border-radius: 10px;
padding: 10px;
box-shadow: 0 0 10px;
}
</style>
案例:作用域插槽
Father.vue
typescript
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Game>
<template v-slot:games="params">
<ul>
<li v-for="g in params.games" :key="g.id">{{ g.name }}</li>
</ul>
</template>
</Game>
<Game v-slot:games="{games}">
<ol>
<li v-for="g in games" :key="g.id">{{ g.name }}</li>
</ol>
</Game>
<Game v-slot:games="params">
<h3 v-for="g in params.games" :key="g.id">{{ g.name }}</h3>
</Game>
</div>
</div>
</template>
<script setup lang="ts" name="Category">
import Game from './Game.vue';
</script>
<style scoped>
.father {
background-color: rgb(165, 164, 164);
padding: 10px;
border-radius: 10px;
}
.content {
display: flex;
justify-content: space-evenly;
}
img,
video {
width: 100%;
}
</style>
Child.vue
typescript
<template>
<div class="game">
<h2>游戏列表</h2>
<slot name ="games" :games="games"></slot>
</div>
</template>
<script setup lang="ts" name="Game">
import {reactive } from 'vue';
let games = reactive([
{id:'001',name:'英雄联盟'},
{id:'002',name:'王者农药'},
{id:'003',name:'红色警戒'},
{id:'004',name:'斗罗大陆'},
])
</script>
<style scoped>
.game {
width: 200px;
height: 300px;
background-color: skyblue;
border-radius: 10px;
box-shadow: 0 0 10px;
}
h2 {
background-color: orange;
text-align: center;
font-size: 14px;
font-weight: 800;
}
</style>
案例:组件通信1
Father.vue
typescript
<template>
<div class="father">
<h3>父组件</h3>
<h4>父亲的玩具:{{ car }}</h4>
<h4>儿子的玩具:{{ 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(v:string){
toy.value = v
}
</script>
<style scoped>
.father {
background-color: rgb(165,164,164);
padding: 20px;
border-radius: 10px;
}
</style>
Child.vue
typescript
<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('奥特玛')
defineProps(['car','sendToy'])
function send() {
}
</script>
<style scoped>
.child {
background-color: skyblue;
padding:10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
</style>
案例:组件通信2-customEvent
typescript
<template>
<div class="father">
<h3>父组件</h3>
<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
<!-- // <button @click="test()">点我</button> -->
<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(val:string) {
console.log('saveToy',val)
toy.value = val
}
</script>
<style scoped >
.father {
background-color: rgb(165,164,164);
padding: 20px;
border-radius: 10px;
}
.father button {
margin-right: 5px;
}
</style>
typescript
<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>
<style scoped>
.child {
background-color: rgb(76,209,76);
padding: 10px;
margin-top: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
</style>
案例:组件通信3-mitt
typescript
<template>
<div class="father">
<h3>父组件</h3>
<Child1 />
<Child2 />
</div>
</template>
<script setup lang="ts" name="Father">
import Child2 from './Child2.vue';
import Child1 from './Child1.vue';
</script>
<style scoped>
.father{
background-color: yellow;
padding: 20px;
border-radius: 10px;
}
</style>
typescript
<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>
<style scoped>
.child1 {
margin-top: 50px;
background-color: skyblue;
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
.child1 button {
margin-right: 10px;
}
</style>
typescript
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>电脑::{{ computer }}</h4>
<h4>玩具:{{ toy }}</h4>
</div>
</template>
<script setup lang="ts" name="Child2">
import { onUnmounted, ref } from 'vue';
let computer = ref('联想')
let toy = ref('')
//数据
import emitter from '@/utils/emitter';
emitter.on('send-toy', (val: any) => {
console.log('Received value:', val); // 确认 val 的值
toy.value = val; // 更新 toy 的值
});
onUnmounted(()=>{
emitter.off('send-toy')
})
</script>
<style scoped>
.child2 {
margin-top: 50px;
background-color: rgb(133, 112, 218);
padding: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
}
.child1 button {
margin-right: 10px;
}
</style>
案例:组件通信4
typescript
<template>
<div class="father">
<h3>父组件</h3>
<!---v-model 用在html标签上-->
<!-- <input type="text" v-model="username"> -->
<!--<input type="text" :value="username" @input="username"=(<HTMLInputElement>$event.target).value-->
<!-- <AtHome
:modelValue="username" @update:modelValue="username = $event"/>
-->
<AtHome v-model:name="username" v-model:pwd="password"/>
<!-- <AtHome v-model="username" /> -->
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue"
import AtHome from "./AtHome.vue";
let username = ref('zhangsan')
let password = ref('123456')
</script>
<style scoped>
.father {
padding: 20px;
background-color: rgb(165, 164, 164);
border-radius: 10px;
}
</style>
typescript
<template>
<input type="text"
:value="name"
@input="emit('update:name',(<HTMLInputElement>$event.target).value)">
<input type="text"
:value="pwd"
@input="emit('update:pwd',(<HTMLInputElement>$event.target).value)">
</template>
<script setup lang="ts" name="AtHome">
defineProps(['name','pwd'])
const emit = defineEmits(['update:name','update:pwd'])
</script>
<style scoped>
input {
border:2px solid black;
background-image: linear-gradient(45deg,red,yellow,green);
height:30px;
font-size:20px;
color: white;
}
</style>
案例:组件通信5
typescript
<template>
<div class="grand-child">
<h3>孙组件</h3>
<h4>{{ a }}</h4>
<h4>{{ b }}</h4>
<h4>{{ c }}</h4>
<h4>{{ d }}</h4>
<button @click="updateA(1)">点我更新爷爷</button>
</div>
</template>
<script setup lang="ts" name="GrandChild">
defineProps(['a','b','c','d','updateA'])
</script>
<style scoped>
.grand-child {
background-color: orange;
padding:20px;
margin-top: 20px;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
typescript
<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" :updateA="updateA"/>
</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)
function updateA(val:number) {
a.value += val
}
</script>
<style scoped>
.father {
background-color: rgb(165,164,164);
padding:20px;
border-radius: 10px;
}
</style>
typescript
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild v-bind="$attrs"/>
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from "./GrandChild.vue"
</script>
<style scoped>
.child {
background-color: skyblue;
padding:20px;
margin-top: 20px;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
案例:组件通信6
typescript
<template>
<div class="father">
<h3>父组件</h3>
<h4>房产:{{ house }}</h4>
<button @click="changeToy">修改child1玩具</button>
<Child1 ref="c1"/>
<button @click="changeToy2">修改child2玩具</button>
<button @click="getAllChild($refs)">获取所有子组件实例对象</button>
<Child2 ref="c2"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import { ref } from 'vue'
let house = ref(4)
let c1 = ref()
function changeToy(){
console.log(c1.value)
c1.value.toy = "杰瑞"
}
let c2 = ref()
function changeToy2(){
c2.value.computer = "华硕"
}
function getAllChild(obj:any){
for (let key in obj){
obj[key].book +=3
}
}
defineExpose({house})
</script>
<style scoped >
.father {
background-color: rgb(165,164,164);
padding:20px;
border-radius: 10px;
}
</style>
typescript
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>儿子1的玩具:{{ toy }}</h4>
<h4>儿子1的书籍:{{ book }}本</h4>
<button @click="minusHouse($parent)">干掉父亲的一套房产</button>
</div>
</template>
<script setup lang="ts" name="Child2">
import { ref } from 'vue';
let toy = ref('汤姆')
let book = ref(3)
defineExpose({toy,book})
function minusHouse(parent:any) {
parent.house -= 1
}
</script>
<style scoped>
.child1 {
margin-top: 20px;
padding: 20px;
background-color: skyblue;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
typescript
<template>
<div class="child2">
<h3>子组件2</h3>
<h4>儿子2的玩具:{{ computer }}</h4>
<h4>儿子2的书籍:{{ 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>
<style scoped >
.child2 {
margin-top: 20px;
padding:20px;
background-color: orange;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
案例:组件通信7
typescript
<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(val:number){
money.value -= val
}
provide('moneyContext',{money,updateMoney})
provide('che',car)
</script>
<style scoped>
.father {
background-color: rgb(165,164,164);
padding:20px;
border-radius: 10px;
}
</style>
typescript
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild/>
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue'
</script>
<style scoped>
.father {
margin-top: 20px;
background-color: skyblue;
padding:20px;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
typescript
<template>
<div class="grand-child">
<h3>我是孙组件</h3>
<h4>钱:{{ money }}</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:(parma:number)=>{}})
let car = inject('car',{brand:'未知',price:0})
</script>
<style scoped>
.grand-child{
background-color: orange;
padding:20px;
border-radius: 10px;
box-shadow: 0 0 10px black;
}
</style>
案例:组件通信8
typescript
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Category >
<template v-slot:s2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
</template>
<template v-slot:s1>
<h2>热门游戏列表</h2>
</template>
</Category>
<Category >
<template v-slot:s2>
<img src="./tmp.png" alt="111">
</template>
<template v-slot:s1>
<h2>今日美食城市</h2>
</template>
</Category>
<Category >
<template #s1>
<h2>今日影视推荐</h2>
</template>
<template #s2>
<video src="./1.mp4" alt="222" controls></video>
</template>
</Category>
</div>
</div>
</template>
<script setup lang="ts" name="Category">
import { reactive,ref } from 'vue';
import Category from './Category.vue';
let games = reactive([
{id:'001',name:'英雄联盟'},
{id:'002',name:'王者农药'},
{id:'003',name:'红色警戒'},
{id:'004',name:'斗罗大陆'},
])
let imgUrl = ref('@/09_slot/tmp.png')
let mp4Url = ref('./1.mp4')
</script>
<style scoped>
/* .category {
background-color: rgb(165,164,164);
padding:10px;
border-radius: 10px;
} */
.content {
display: flex;
justify-content: space-evenly;
}
img,video {
width: 100% ;
}
h2 {
background-color: orange;
text-align: center;
font-size: 14px;
font-weight: 800;
}
</style>
typescript
<template>
<div class="category">
<h2>{{ title }}</h2>
<slot name="s1">默认内</slot>
<slot name="s2">默认内</slot>
</div>
</template>
<script setup lang="ts" name="Category">
defineProps(['title'])
</script>
<style scoped>
.category {
background-color: skyblue;
border-radius: 10px;
box-shadow: 0 0 10px;
padding:10px;
width:200px;
height:300px;
}
h2 {
background-color: orange;
text-align: center;
font-size: 14px;
font-weight: 800;
}
</style>