render函数
import Vue from 'vue'
在main.js中直接引入vue,其实引入的是runtime运行版的vue,精简掉了模板解析器,所以不能使用template配置项。
但我们可以使用render函数实现模板解析:
render(createElement) {
return createElement(App)
}
由于无需使用this,所以可以用箭头函数简写:
render: h => h(App)
render函数只用在 main.js 中解析模板即可,在 .vue 模块中的template,另有脚手架的模板解析器处理。
父组件给子组件传递数据
通过父组件给子组件传递props实现。
子组件给父组件传递数据
通过父组件给子组件传递函数类型的props,子组件中通过函数参数传递数据实现。
或者,通过父组件给子组件绑定自定义事件,子组件触发自定义事件实现:
父组件中绑定自定义事件 方式一:
<Demo @event="test"/>
<!-- <Demo v-on:event="test"/> -->
父组件中绑定自定义事件 方式二:
<Demo ref="demo"/>
......
mounted() {
this.$refs.demo.$on('event', this.test)
}
子组件中触发自定义事件:
this.$emit('event', data) // data为要给父组件传递的数据
子组件中解绑自定义事件:
this.$off('event')
注意点:
- 自定义事件也可以使用事件修饰符,或$once等
- 组件上也可以绑定原生DOM事件,但需要加上
.native
修饰符 - 事件的回调函数写在父组件中
- 通过ref方式绑定自定义事件时,回调函数要么写在methods里面,要么写成箭头函数,否则this指向会出问题
任意组件间通信
全局事件总线GlobalEventBus可以实现任意组件间的通信,但更常用在跨级组件间通信,以及同级组件间通信。
原理:构建出一个vm或vc实例对象作为全局事件总线,添加到合适的位置,使之可以被所有的组件访问到,再分别给这个全局事件总线绑定自定义事件,从而实现任意组件间的通信。
由于每次生成出来的VueComponent都是一个全新不同的构造函数,所以不能在VueComponent的原型对象上添加全局事件总线。又因为VueComponent.prototype.__proto__
=== Vue.prototype
的存在,所以可以在Vue的原型对象上添加全局事件总线,从而使得所有的vc都可以访问得到。
在main.js中安装全局事件总线:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this // $bus为全局事件总线,this为vm实例对象
},
......
})
接受数据的组件中给$bus绑定自定义事件,并设置在此组件销毁后解绑该事件:
methods() {
test(data) {......} // data为要接受的数据
}
......
mounted() {
this.$bus.$on('event',this.test)
}
beforeDestroy() {
this.$bus.$off('event')
}
提供数据的组件中触发$bus上的自定义事件:
this.$bus.$emit('event', data) // data为要传递的数据
任意组件间通信还可以通过 消息订阅与发布 实现,但需要引入第三方库,因此更常用全局事件总线。
Vue封装的过渡与动画
用于在插入、更新、移除DOM元素时,在合适的时候给元素添加样式类名。以下以过渡为例:
在样式中准备过渡,可以自己写也可以引入第三方样式库:
v-enter {
/* 进入的起点 */
}
v-enter-to {
/* 进入的终点 */
}
v-enter-active {
/* 进入的过程中(持续时间、动画曲线等) */
}
v-leave {
/* 离开的起点 */
}
v-leave-to {
/* 离开的终点 */
}
v-leave-active {
/* 离开的过程中(持续时间、动画曲线等) */
}
在结构中使用<transition>
包裹要过渡的元素:
<transition>
<!-- 需要过渡效果的元素 -->
</transition>
如果要为多个transition分别配置name属性,则样式中
v-xxx
要改为demoname-xxx
。若同一个transition中有多个元素需要过渡,则需要改用
<transition-group>
包裹元素,且每个元素都需要指定key值。
配置代理服务器
通过在vue.config.js中配置代理服务器,使得代理服务器的地址和端口号与本机相同,可以解决浏览器与服务器之间通信的跨域问题。
简单配置代理:
devServer: {
proxy: "http://localhost:5000" //代理目标的基础路径
}
Tips:
- Vue中请求资源,直接发给前端本机即可
- 但这种方式不能配置多个代理,也不能灵活地控制请求是否走代理
- 会优先匹配前端本机的资源,若本机不存在,才会走代理转发给目标服务器
具体配置代理规则:
devServer: {
proxy: {
'/api1': { //匹配所有以/api1开头的请求路径
target: 'http://localhost:5000', //代理目标的基础路径
changeOrigin: true, //改变请求头的host地址为目标服务器的地址
pathRewrite: {'^/api1': ''} //去掉匹配路径前缀
},
'/api2': { //匹配所有以/api2开头的请求路径
target: 'http://localhost:5001', //代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
Tips:
- 这种方式可以配置多个代理,且可以灵活地控制请求是否走代理
- Vue中请求资源时必须加路径前缀,并在代理配置中去掉前缀
Vue中常用的两个Ajax库
- axios:尤雨溪亲自推荐,当今最常用
- vue-resource:Vue1.0时代遗留项目较多使用,当今已缺乏维护
slot插槽
插槽可以让父组件向子组件的指定位置插入HTML结构。它也是组件间的一种通信方式,适用于父组件给子组件传递数据,只不过传递的数据为HTML结构。
slot插槽分为:默认插槽,具名插槽,作用域插槽。
默认插槽:最简单直接的插槽类型。
<!-- 父组件中 -->
<Category>
<div>html结构</div>
</Category>
<!-- 子组件中 -->
<template>
<div>
<slot>插槽默认内容...</slot>
</div>
</template>
具名插槽:具有名称的插槽,用于多个插槽共存。
<!-- 父组件中 -->
<Category>
<template slot="center"> <!-- 老式写法 -->
<div>html结构1</div>
</template>
<template v-slot:footer> <!-- 新式写法 -->
<div>html结构2</div>
</template>
</Category>
<!-- 子组件中 -->
<template>
<div>
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>
作用域插槽:数据在子组件的自身,但根据数据生成的HTML结构需要组件的使用者(父组件)来决定。
<!-- 父组件中 -->
<Category>
<template scope="scopeData"> <!-- 老式写法 -->
<!-- 生成的是ul列表 -->
<ul>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ul>
</template>
</Category>
<Category>
<template slot-scope="scopeData"> <!-- 新式写法 -->
<!-- 生成的是h4标题 -->
<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
</template>
</Category>
<!-- 子组件中 -->
<template>
<div>
<slot :games="games"></slot>
</div>
</template>
<script>
export default {
name: "Category",
//数据在子组件自身
data() {
return {
games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
};
},
};
</script>
Tips:
scope="scopeData"
收到的是一个对象形式,包含了插槽提供的数据- 作用域插槽也可以有名称,和具名插槽一样多个作用域插槽共存