Vue学习笔记05 组件的自定义事件-组件通信-$nextTick-脚手架解决ajax跨域-插槽-过渡动画

本文详细介绍了Vue中父子组件的通信方式,包括props、自定义事件、$emit、$on、$off的使用,以及组件的原生事件、全局事件总线、消息订阅发布。还讲解了Vue的动画效果transition、transition-group,以及如何解决跨域问题和使用Vue CLI配置代理。此外,还涵盖了插槽的概念,包括默认插槽、具名插槽和作用域插槽的用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue学习笔记05

父组件给子组件传值

props用于让组件接受外部传过来的值

//父组件传值 age传的是字符串"18"
<Student name="李四" sex="女" age="18"/>
//vbind动态绑定,绑定是引号里的js表达式的执行的结果,18
<Student name="李四" sex="女" :age="18"/>

//写法1:子组件接受值,简单接受
props:['name','sex','age']

//写法2:子组件接受值,设置希望类型
props:{
	name:String,
	sex:String,
	age:Number	
}

//写法3: 子组件接受值,完整写法
props:{
	name:{
		type:String,
		required:true //是否必须
	},
	age:{
		type:Number,//类型
		default:99 //默认值
	}
}

props是只读属性,子组件不可以修改传入的值。
如果想要修改可以使用中间变量

{{myAge}} //模板中使用

data(){
	myAge:this.age //中间变量
},
props:['age'] //优先被设置在vc组件上

注意点

如果子组件不使用prop,子组件的$attrs里会存储传过来的属性,子组件的vc实例上不会存储
如果子组件使用prop,子组件的vc实例上会直接存储传过来的属性,子组件的$attr里不会存储

子组件给父组件传值

  1. 将自定义事件绑定在子组件的实例vc上,回调函数是在父组件中
    1.1 在父组件中自定义事件@自定义事件=’事件回调'
    1.2 在父组件中采用ref获取到子组件的实例,采用$on(‘事件名’,回调函数)绑定自定义事件
  2. 子组件触发自定义事件this.$emit(‘事件名’,数据),子组件解绑自定义事件this.$off()

父组件接受子组件的传值 通过函数

v-model绑定的值不能是props传过来的值,因为props的值是不可以修改的

父组件给子组件传递函数,子组件调用传参,父组件获得子组件的参数值

//父组件
<MyHeader :addTodo="addTodo"/>
export default {
	name:'App',
	components:{MyHeader},
	methods: {
		//添加一个todo
		addTodo(todoObj){
		this.todos.unshift(todoObj)
	  }
}
//子组件
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
export default {
	name:'MyHeader',
	props:['addTodo'],//接收从App传递过来的addTodo
	methods: {
		add(){
		const todoObj ={id:nanoid(),title:this.title,done:false}
		//通知App组件去添加一个todo对象
		this.addTodo(todoObj)
		}
	}
}

组件的自定义事件

内置指令->HTML元素使用
自定义指令-> 组件使用

事件绑定的第一种写法 @或v-on

@或v-on 绑定在子组件的vc上

绑定事件:使用@或v-on:将回调函数绑定在子组件的vc上
触发事件:在子组件中触发,$emit(‘事件名’,参数1…,参数2…)

<!-- 第一种写法,使用@或v-on 绑定在子组件的vc上 --> 
<Student @getName="getStudentName" @demo="m1"/> 
<!-- 一次性事件 -->
<Student @getName.once="getStudentName" @demo="m1"/>
 
methods: {
	getSchoolName(name){
			console.log('App收到了学校名:',name)
}

<!--Studetn子组件传值-->
<button @click="sendStudentlName">把学生名给App</button>

methods:{
	sendStudentlName(){
	//触发Student组件实例身上的getName事件
		this.$emit('getName',this.name)
	}
}

事件绑定的第二种写法:使用ref + $on

this.$refs.xxx获取到组件的vc实例
更灵活,可以控制绑定时间

使用$on绑定在子组件上

$on('事件名',回调函数) 给组件绑定自定义事件

<!-- 第二种写法,使用ref -->
<Student ref="student"/>

//父组件挂载完毕时
mounted(){
this.$refs.student.$on('atguigu',this.getStudentName)
//this.$refs.student.$once('atguigu',this.getStudentName)一次性事件
}

需要注意回调函数的定义位置,定义在methods中,或者使用箭头函数,不然this的指向可以出问题。

事件触发解绑 $emit $off

触发事件:在绑定事件的组件中触发,$emit('事件名',参数1..,参数2..)
解绑一个事件: 在绑定事件的组件中触发,off('事件名')
解绑多个事件: 在绑定事件的组件中触发,$off(['事件名1','事件名2'...])
解绑所有事件: 在绑定事件的组件中触发,off()

组件绑定原生事件

自定义指令-> 组件使用,所以如果直接写原生事件名会被认为时自定义事件

//需要Student组件$emit触发click事件之后,show回调才会被调用
<Student ref="student" @click="show"/>

修饰符native表明该事件是内置事件

//需要Student组件$emit触发click事件之后,show回调才会被调用
<Student ref="student" @click.native="show"/>

全局事件总线 任意组件间通讯

全局事件总线的特点
1.所有组件都可以看见
2.需要有$on$off$emit

在这里插入图片描述

VueComponent.prototype.prototype.proto === Vue.prototype
作用:让组件实例对象vc可以访问到Vue原型上的属性和方法

思路
1.事件总线需要在Vue显式原型上,这样所有的组件都可以看见
2.事件总线需要使用Vue显式原型里的$on$off$emit函数,所以事件总线需要能看见Vue显式原型,事件总线可以设置成Vue的实例

错误写法

import Vue from 'vue'
const vm = new Vue({
	el:'#app',
	render:h=>h(App) //①
})
//报错
Vue.prototype.$bus= vm; 

上述写法报错的原因
①执行完后,App整个组件已经渲染到了页面上,此时组件中的$on绑定事件已经执行完毕,此时已经晚了。

正确写法
可以写在befoteCreate生命周期钩子里,befoteCreate的this指向Vue实例(new Vue())

import Vue from 'vue'
const vm = new Vue({
	el:'#app',
	render:h=>h(App),
	beforeCreate(){
	Vue.prototype.$bus= this;//安装全局事件总线
	}
})

组件中通过this.$bus.$on this.$bus.$off `this. b u s . bus. bus.emit 使用

全局事件总线所有组件都可以看见,所以要小心事件名重复。
最好在beforeDestroy钩子中,使用$off去解绑当前组件所用到的事件

消息订阅与发布 任意组件间通讯

消息订阅与发布
1.订阅消息:消息名 谁需要数据谁订阅
2.发布消息:消息内容 提供数据的发布消息

依赖消息订阅与发布库,这里选择pubsub-js

//谁需要谁引用
import pubsub from 'pubsub.js'
//订阅消息,每次订阅返回一个新的消息号,
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
		console.log("订阅hello消息的回调函数,当hello消息被发布时调用")
}
//发布消息
pubsub.publish('hello',666)
//最好在beforeDestroy钩子中取消消息
pubsub.unsubscribe(消息号);

事件总线区别
对于同名的消息,消息订阅和发布可以取消特定消息号的一个消息,但是事件总线取消同名的一类消息

$nextTick(callback)


$nextTick指定的回调函数callback会在DOM节点更新完毕之后再执行

使用场景
当改变数据后,要基于更新后的新DOM进行操作时,要在nextTick所指定的回调函数中执行。

动画效果 transition

作用:在插入、更新或移除DOM时,在合适的时候给元素添加样式名

<transition></transition>包裹需要动画的代码块,Vue解析时并不会生成真实的标签

通过CSS特定的选择器名字设置动画的执行时机

当有多个动画有不同的效果时,可以给transition标签添加name属性,那么对应的.v-enter-active等应该变成.hh-enter-active

<!--开始的时候isShow为真,但是开始并没有进入的动画,添加appear后初次渲染就有效果-->
<transition name="hh" appear>
	<h1 v-show="isShow">你好啊!</h1>
</transition>

<style>
/*进入时激活的样式*/
.v-enter-active{
	animation: ranan 0.5s linear;
}
/*离开时激活的样式*/
.v-leave-active{
	animation: ranan 0.5s linear reverse;
}

@keyframes ranan {
	from{
		transform: translateX(-100%);
	}
	to{
		transform: translateX(0px);
	}
}
</style>

可以不采用定义动画的方式实现上述效果,可以使用过渡实现

/*进入的过程中,离开的过程中*/
.v-enter-active,.v-leave-active{
	transition:0.5s linear;
}
/*进入的起点样式*/
.v-enter{
	transform: translateX(-100%);
}
/*进入的终点样式*/
.v-enter-to{
	transform: translateX(0);
}
/*离开的起点样式*/
.v-leave{
	transform: translateX(0);
}
/*进入的终点样式*/
.v-leave-to{
	transform: translateX(-100%);
}

transition-group

<transition></transition>里面只能有一个元素
<transition-group></transition-group>里面可以放多个元素,但是每个元素必须要绑定key属性

第三方动画库Animate.css,引入直接import 'animate.css'

解决ajax跨域问题 配置代理

同源原则:协议名、主机名、端口号都一样
在这里插入图片描述
真正意义上的跨域cors
后端使用cors解决跨域,添加特殊的响应头,浏览器看见特殊的响应头,虽然跨域但是服务器同意把数据给客户端,浏览器就把数据给客户端

代理服务器

代理服务器和我们客户端同源,利用服务器与服务器之间没有同源策略的方法实现。(因为服务器之间不适用ajax通信)
在这里插入图片描述

利用脚手架配置代理服务器

方式1 不常用

修改vue.config.jsvue-cli配置文件

module.exports = {
	devServer:{
		proxy:'http:localhost:5000' //代理服务的端口会根据我们客服端的端口自动的配置,这里写需要代理的服务器的地址
		}
}

说明
1.发送请求的时候,直接向代理服务器要数据
2.public目录就是代理服务器的根目录
3.代理服务器先会在自己的文件中查找,如果没有再转发给服务器

缺点
1.只能配置一个代理
2.不可以灵活转发,没办法控制走不走代理

方式2 请求前缀

请求前缀在端口号的后面
如:http:localhost:8080/student -> http:localhost:8080/xxx/student
如果这样直接给服务器,服务器收到的是http:localhost:8080/xxx/student,我们需要把/xxx去掉,需要重写路径

module.exports = {
	devServer:{
		proxy:{
			'/xxx':{
				//遇见xxx前缀的请求,走代理去服务器端获取
				target:'http:localhost:5000',
				pathRewrite:{'^/xxx':'']//重写path把开头的/xxx前缀删除
				//ws:true, 用于支持websocket
				//changeOrigin:true,是否告诉服务器请求源的真实信息,比如这是一台代理服务器端口号是8080。用于控制请求头中的host值
			},
			'/yyy':{
				target:'http:localhost:5001',
				pathRewrite:{'^/yyy':'']
			}
		}
	}
}

插槽

作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件->子组件

父组件传的html结构会以虚拟节点的形式存储在子组件vc实例的$slots属性里

默认插槽

<!--解析到img标签后,img应该放在Category组件里的哪个位置呢?-->
<Category title="美食" >
	<img src="" alt="">
</Category>

<!--Category组件里使用slot告诉img放在这里-->
<div>
<h1>Category组件</h1>
<slot>这段文字是默认值,当使用者没有传递具体结构时出现<slot>
</div>

具名插槽

使用<slot name="xxx">给插槽命名,使用 slot="xxx"选择放入哪个插槽

h4和div都想放在footer插槽里面,但是不想再加一个div结构,就可以选择使用<template >标签
<template >标签有个独特的具名插槽写法<template v-slot:footer>,Vue3只支持这种具名插槽写法

<Category title="电影">
	<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
	<template v-slot:footer>
	<!--<template slot="footer">-->
	<div class="foot">
		<a href="http://www.atguigu.com">经典</a>
		<a href="http://www.atguigu.com">热门</a>
		<a href="http://www.atguigu.com">推荐</a>
	</div>
	<h4>欢迎前来观影</h4>
</template>
</Category>


<!--Category组件-->
<div>
<h1>Category组件</h1>
<slot name="center">这段文字是默认值,当使用者没有传递具体结构时出现<slot>
<slot name="footer">这段文字是默认值,当使用者没有传递具体结构时出现<slot>
</div>

作用域插槽

使用场景:数据在插槽位置,但是根据数据生成的结构需要父组件来决定

数据在子组件(作用域),结构由父组件传。
数据: 子 -> 父 结构:父 -> 子

1.<slot :xxxx="数据">将数据传给父组件
2.父组件(给插槽传结构的代码)外侧包裹<template scope="yyyy">标签,也可以写成<template slot-scope="yyyy">yyyy接收到的是插槽传过来的{xxxx:数据}
3.父组件接收的数据是一个对象,对象包含传过来的值。也就是说传过来的值外层包裹了一层对象,所以起名的时候yyy可以和xxx不一样。

<Category title="游戏">
	<template scope="ranan">
		<ul>
			{{ranan}} <!--接收到{game:['红色警戒','穿越火线','劲舞团','超级玛丽'],mag:"hello"}-->
		</ul>
 </template>
</Category>

<!--category组件-->
<template>
	<div class="category">
		<slot :game="games">我是默认的一些内容</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
		data() {
			return {
				games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
			}
		},
	}
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值