组件

组件化开发利于复用,结构清晰;就像任何复杂的结构都需要分层一样,现代页面更适合分组件开发。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 },
});
  1. school 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的。

  2. 我们只需要写<school/><school></school>,Vue 解析时会帮我们创建 school 组件的实例对象, 即 Vue 帮我们执行的:new VueComponent(options)。

  3. 特别注意:每次调用 Vue.extend,返回的都是一个全新的 VueComponent

  4. 关于 this 指向:

    • 组件配置中: data 函数、methods 中的函数、watch 中的函数、computed 中的函数,它们的 this 均是【VueComponent 实例对象】。
    • new Vue(options)配置中: data 函数、methods 中的函数、watch 中的函数、computed 中的函数,它们的 this 均是【Vue 实例对象】。
  5. VueComponent 的实例对象,以后简称 vc(也可称之为:组件实例对象);Vue 的实例对象,以后简称 vm。

VueComponent.prototype 的指向

组件原型链

  1. 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
  2. 为什么要有这个关系:让组件实例对象(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

  1. vue.js 与 vue.runtime.xxx.js 的区别:

    • vue.js 是完整版的 Vue,包含:核心功能+模板解析器。
    • vue.runtime.xxx.js 是运行版的 Vue,只包含:核心功能;没有模板解析器。
  2. 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。

组件间通信

父子组件

  1. 通过父组件给子组件传递函数类型的 props 实现:子给父传递数据
  2. 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据

事件总线

应用任意组件间通信:

  • 所有组件实例可访问,在 Vue.prototype 上设置属性即可
//create vm
new Vue({
  el: "#app",
  render: (h) => App,
  beforeCreate() {
    // install global event bus
    Vue.prototype.$bus = this;
  },
});






 


Vuex

Vuex 的原理

Vuex 是 Vue 用来统一管理共享状态的插件,可用于任意组件间通信。

vuex原理图

  • 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