组件
组件化开发利于复用,结构清晰;就像任何复杂的结构都需要分层一样,现代页面更适合分组件开发。Vue 维护了全新的.vue
文件,称为单文件组件 SFC,下面主要介绍非单文件组件,理解它是开发 SFC 的基础。
组件的应用
定义组件(创建组件)
- 使用 Vue.extend(options)创建,其中 options 和 new Vue(options)时传入的那个 options 几乎一样,但也有点区别; 区别如下:
- el 不要写,为什么? —— 最终所有的组件都要经过一个 vm 的管理,由 vm 中的 el 决定服务哪个容器。
- data 必须写成函数,为什么? —— 避免组件被复用时,数据存在引用关系。
- 备注:
- 使用 template 可以配置组件结构。
- const school = Vue.extend(options) 可简写为:const school = options
注册组件
- 1.局部注册:靠 new Vue 的时候传入 components 选项
- 2.全局注册:靠 Vue.component('组件名',组件)
使用组件(写组件标签)
<componentName></componentName>
组件的本质
VueComponent 构造函数
//定义school组件
const school = Vue.extend({
name: "school",
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data() {
return {
name: "江西农业大学",
address: "南昌",
};
},
methods: {
showName() {
console.log("showName", this);
},
},
});
const test = Vue.extend({
template: `<span>zhang13pro</span>`,
});
//定义hello组件
const hello = Vue.extend({
template: `
<div>
<h2>{{msg}}</h2>
<test></test>
</div>
`,
data() {
return {
msg: "你好啊!",
};
},
components: { test },
});
//创建vm
const vm = new Vue({
el: "#root",
components: { school, hello },
});
school 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的。
我们只需要写
<school/>
或<school></school>
,Vue 解析时会帮我们创建 school 组件的实例对象, 即 Vue 帮我们执行的:new VueComponent(options)。特别注意:每次调用 Vue.extend,返回的都是一个全新的 VueComponent
关于 this 指向:
- 组件配置中: data 函数、methods 中的函数、watch 中的函数、computed 中的函数,它们的 this 均是【VueComponent 实例对象】。
- new Vue(options)配置中: data 函数、methods 中的函数、watch 中的函数、computed 中的函数,它们的 this 均是【Vue 实例对象】。
VueComponent 的实例对象,以后简称 vc(也可称之为:组件实例对象);Vue 的实例对象,以后简称 vm。
VueComponent.prototype 的指向
- 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
- 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue 原型上的属性、方法。
其实 Vue 内部重写了 VueComponent 函数的原型 ✅
var Sub = function VueComponent(options) {
this._init(options);
};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
单文件组件
单文件组件就是.vue
格式结尾的文件,将 HTML、CSS、JS 维护在同一个文件里。
<template>
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
//引入组件
import School from "./School.vue";
import Student from "./Student.vue";
export default {
name: "App",
components: {
School,
Student,
},
};
</script>
渲染函数
当我们在 main.js 中引用单文件组件时,不能像之前那样使用 template
option。因为默认引入的 vue 是不包括模板解析器部分的,所以必须使用 render 函数渲染 template 里的内容。
//引入Vue
import Vue from "vue";
//引入App组件,它是所有组件的父组件
import App from "./App.vue";
//创建Vue实例对象---vm
new Vue({
el: "#app",
//render函数完成了这个功能:将App组件放入容器中
render: (h) => h(App),
// template:`<h1>你好啊</h1>`,
});
官方使用 h 指代createElement()
函数。
不同版本的 Vue
vue.js 与 vue.runtime.xxx.js 的区别:
- vue.js 是完整版的 Vue,包含:核心功能+模板解析器。
- vue.runtime.xxx.js 是运行版的 Vue,只包含:核心功能;没有模板解析器。
因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。
组件间通信
父子组件
- 通过父组件给子组件传递函数类型的 props 实现:子给父传递数据
- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据
- vm.$emit
- vm.$refs
- vue3 已移除 - 非兼容
$on绑定$off解绑$once一次性
事件总线
应用任意组件间通信:
- 所有组件实例可访问,在
Vue.prototype
上设置属性即可
//create vm
new Vue({
el: "#app",
render: (h) => App,
beforeCreate() {
// install global event bus
Vue.prototype.$bus = this;
},
});
Vuex
Vuex 的原理
Vuex 是 Vue 用来统一管理共享状态的插件,可用于任意组件间通信。
- actions 对象用来传递更改状态的函数,换句话说,用于响应组件中的动作
- mutations 对象接收函数并执行,用于操作数据(state)
- state 存放共享的状态(数据)
- getters 用于将 state 中的数据进行加工(类似全局的 computed)
Vuex 的使用
// Count.vue
data():{
return{
n:1,
}
},
methods: {
increment() {
// 没有网络请求或其他业务逻辑,越过actions
// this.$store.dispatch("jia", this.n);
this.$store.commit("JIA", this.n);
},
}
// store.js
let actions = {
jia(context,value){
console.log('actions中的jia被调用了')
context.commit('JIA',value)
},
};
let mutations = {
JIA(state, value) {
console.log("mutations中的JIA被调用了");
state.sum += value;
},
};
let state = {
sum: 0,
};
export default new Vuex.Store({
actions,
mutations,
state,
});
map 方法的使用
- mapState 用于映射 state 中的数据为 computed
- mapGetters 用于映射 getters 中的数据为 computed
- mapActions 生成与 actions 对话的方法,既包含
$store.dispatch(xxx)
的函数 - mapMutations 生成与 mutations 对话的方法,既包含
$store.commit(xxx)
的函数
注意
mapActions 和 mapMutations 需要在模板绑定方法时传参,否则默认传递 Event