3872 字
19 分钟
Vue 工程化与组件通信
Vue 工程化开发与组件间通信全解,涵盖脚手架、ESLint、单/多文件组件、父子通信、事件总线、provide/inject、mixin、插件、插槽等,适合 Vue 实战开发者参考。
2026-02-03
0 次
0 人

Vue工程化开发#

脚手架#

创建脚手架#

使用步骤: 1.全局安装(一次):yarn globaladd @vue/clinpm i @vue/cli -g

2.查看 Vue 版本:`vue —version

3.创建项目架子:vue create project-name(项目名-不能用中文)

4.启动项目:yarn servenpm run serve( 看package.json的配置 )

官方文档网址#

修改入口文件等操作,在 vue.config.js中配置

配置参考 | Vue CLI (vuejs.org)

Vuecli自定义创建项目#

步骤:

1、安装脚手架

2、创建项目:

Terminal window
vue create 项目名

3、选择自定义: Manually select features

选择特性:(根据自己的项目来,需要什么选什么,上下键选择空格键选中)

具体选择(根据自己的项目进行选择)

ESLint代码规范#

代码规范:一套写代码的约定规则。例如:“赋值符号的左右是否需要空格""一句结束是否是要加;”…

JavaScript Standard Style(目前市场上使用最多的规范): https://standardis.com/rules-zhcn.html

下面是这份规则中的一小部分:

  • 字符串使用单引号 ‘abc’
  • 无分号 const name =‘zs’
  • 关键字后加空格 if(name =‘ls’){..}
  • 函数名后加空格 function name (arg){…}
  • 坚持使用全等 ===、摒弃 ==

一切不符合规范的代码都会报错

ESLint查找并修正错误#

①手动修正:#

根据错误提示来一项一项手动修改纠正, 如果你不认识命令行中的语法报错是什么意思,根据错误代码去[ESLint 规则表]中查找其具体含义

② 自动修正#

基于 VsCode 插件 ESLint ** 高亮错误,并通过配置** 自动 帮助我们修复错误

// 当保存的时候,eslint自动帮我们修复错误"
"editor.codeActionsOnSave": {
"source.fixAll": true
},
//保存代码,不自动格式化'
"editor.formatOnSave":false,

有可能代码声明了变量没有使用等不能自动修正的代码,也会报错,此时得自己修正手动错误

非单文件组件#

基本使用#

Vue中使用组件的三大步骤:

​ 一、定义组件(创建组件) const 变量名 = Vue.extend({这里面配置和new Vue差不多,但是没有el})

​ 二、注册组件 局部注册:new Vue内配置 components 全局注册:Vue.component(‘组件名’,组件)

​ 三、使用组件(写组件标签) 模板内使用<组件名></组件名>

​ 一、如何定义一个组件?

​ 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;

​ 区别如下:

​ 1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

​ 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

​ 备注:使用template可以配置组件结构。

​ 二、如何注册组件?

​ 1.局部注册:靠new Vue的时候传入components选项

​ 2.全局注册:靠Vue.component(‘组件名’,组件)

​ 三、编写组件标签:

<div id="id" class="">
<h1>{{str}}</h1>
<!-- 使用组件 -->
<school></school>
<hr>
<students></students>
<all></all>
</div>
<div id="id2" class="">
<all></all>
</div>
<script src="../../vue.js"></script>
<script>
// 创建组件
const school = Vue.extend({
template: `
<div>
<div>学校 :{{name}}</div>
<div>地址 :{{address}}</div>
</div>`,
data() {
return {
name: '清华',
address: '北京'
}
}
})
const students = Vue.extend({
template: `
<div>
<div>学生 :{{name}}</div>
<div>年龄 :{{age}}</div>
</div>
`,
data() {
return {
name: '卡卡',
age: 20
}
}
})
const all = Vue.extend({
template: `<div><h2>全局配置</h2></div>`
})
// 全局注册
Vue.component('all', all)
new Vue({
el: '#id',
data: {
str: '非单文件组件'
},
// 局部注册组件
components: {
school,
students
}
})
new Vue({
el: '#id2'
})
</script>

注意点#

1.关于组件名:

​ 一个单词组成:

​ 第一种写法(首字母小写):school

​ 第二种写法(首字母大写):School

​ 多个单词组成:

​ 第一种写法(kebab-case命名):my-school

​ 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

​ 备注:

​ (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

​ (2).可以使用name配置项指定组件在开发者工具中呈现的名字。

2.关于组件标签:

​ 第一种写法:

​ 第二种写法:

​ 备注:不用使用脚手架时,会导致后续组件不能渲染。

3.一个简写方式:

​ const school = Vue.extend(options) 可简写为:const school = options

VueComponent(组件实例对象:vc)#

关于VueComponent:

​ 1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

​ 2.我们只需要写,Vue解析时会帮我们创建school组件的实例对象,

​ 即Vue帮我们执行的:new VueComponent(options)。

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

​ 4.关于this指向:

​ (1).组件配置中:

​ data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。

​ (2).new Vue(options)配置中:

​ data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

​ 5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。

​ Vue的实例对象,以后简称vm。

单文件组件#

使用#

1.创建 .vue 文件 ,里面配置,一个文件就是一个组件,最终都要被App.vue管理,之后再到入口文件引入

Student组件 (子组件)
<template>
<!-- 配置模板结构 -->
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
</template>
<script>
// 默认导出
export default {
//这里面配置组件信息
name:'Student',//组件名,一般和文件名相同
data(){
return {
name:'张三',
age:18
}
};
</script>
<style>
/*样式结构*/
</style>
App.vue 统帅组件(父组件/根组件)
<template>
<div>
<Student></Student>
</div>
</template>
<script>
//引入 Student组件
import Student from "./components/Student";
export default {
//组件注册
components: {
Student
},
};
</script>
入口文件
//引入Vue 和 App组件
import Vue from 'vue'//这是个不完整的vue,只包含核心,没有模板解析器
import App from './App.vue'
new Vue({
template: `<app></app>`,
el: '#app',
render: h => h(App)//引入的vue不包含模板解析器,所以要用render
})

关于不同版本的Vue#

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

​ (1).vue.js是完整版的Vue,包含:核心功能+模板解析器。

​ (2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。

​ 2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用

​ render函数接收到的createElement函数去指定具体内容。

注册全局组件#

入口文件中 / main.js中
// 引入组件
import all from './components/all'
// 全局注册
Vue.component('all', all)

组件间通信#

父传子#

prop配置项#

  1. 功能:让组件接收外部传过来的数据

  2. 传递数据:<Demo name="xxx"/>

  3. 接收数据:

    1. 第一种方式(只接收):props:['name']

    2. 第二种方式(限制类型):props:{name:String} 用的最多

    3. 第三种方式(限制类型、限制必要性、指定默认值):

      props:{
      name:{
      type:String, //类型
      required:true, //必要性 ,是否必填
      default:'老王', //默认值
      validator(value){
      //自定义校验逻辑
      return 是否通过校验
      //if (value > 100) {
      //return true
      // } else {
      // console.error('传入的数字必须大于100')
      //return false
      }
      }
      }
      }

    备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

子传父#

this.$emit('事件名',数据)

自定义事件(子传父)#

组件中的通信机制:子组件==>父组件 (子组件 传 数据 给 父组件)

绑定方式:

​ 1.在组件标签中绑定:父组件中 <School @事件名=“回调函数”/><School v-on:事件名=“回调函数”/>

​ 2.用ref绑定:父组件中

<Demo ref="标识名"/>
......
mounted(){
this.$refs.标识名.$on('事件名',回调函数)
}

​ 3.若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

触发自定义事件:触发事件的组件中this.$emit('事件名',参数(根据情况传入参数,可以有多个))

解绑自定义事件:触发事件的组件中

​ 解绑单个 :this.off('事件名')

​ 解绑多个 :this.off(['事件名1','事件名2'])

​ 全部解绑 :this.off()

组件上也可以绑定原生DOM事件,需要使用native修饰符。

注意:通过this.$refs.标识名.$on('事件名',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

全局事件总线(GlobalEventBus)#

是一种组件间的通信机制:(任意组件间的通信)

使用:

​ 1、安装全局事件总线:在入口文件中(main.js 或 index.js)

// 法一:给Vue的一个实例对象安装全局事件总线
// Vue.prototype.$bus = new Vue()
// 法二:在当前管理组件的Vue实例对象的钩子上安装
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})

​ 2.使用:

​ ①哪个组件需要接收数据就在哪个组件的mounted钩子上给$bus注册事件监听

methods(){
demo(data){......}
}
......
mounted() {
//注册事件监听
this.$bus.$on('事件名',this.demo)//可直接写回调函数,建议将回调写到方法中
}

​ ②发送数据的组件中

// 发送
this.$bus.$emit('事件名',数据)

​ ③注册事件监听解的组件绑事件监听

beforeDestroy() {
// 解绑事件监听器
this.$bus.$off('事件名')
}

父传子孙通信-provide&inject配置项#

provide&inject作用:跨层级共享数据,可以理解为后代组件共用的data,但是后代组件需要用inject接收

1.父组件 provide 提供数据

export default {
data() {
return {
color: 'blue',
userInfo: {
name: 'kaka',
age: 17,
},
}
},
provide() {
return {
// 普通类型 【非响应式】
color: this.color,
// 复杂属性 【响应式】
userInfo: this.userInfo,
}
},
}

2.子组件 inject 获取数据

export default {
inject: ['color', 'userInfo'],
}

mixin(混入/合)配置项#

  1. 功能:可以把多个组件共用的配置提取成一个混入对象

  2. 使用方式:

    第一步定义混合——创建一个名为xxx的js文件,在里面配置组件需要共用的部分:

    export default {
    data(){....},
    methods:{....}
    ....
    }

    全局也可以直接 :Vue.mixin({这里面配置})

    第二步使用混入:

    ​ 1.哪个组件需要使用,就引入该混合文件。

    ​ 2.混入

    ​ 全局混入:入口文件中配置:Vue.mixin(xxx) 局部混入:vc中配置:mixins:['xxx']

插件#

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:

    对象.install = function (Vue, options) {
    // 1. 添加全局过滤器
    Vue.filter(....)
    // 2. 添加全局指令
    Vue.directive(....)
    // 3. 配置全局混入(合)
    Vue.mixin(....)
    // 4. 添加实例方法
    Vue.prototype.$myMethod = function () {...}
    Vue.prototype.$myProperty = xxxx
    }
  4. 使用插件:Vue.use(插件名(文件名))

scoped样式#

在组件的样式中,样式默认是混合的,容易造成类名重复,需要用 scoped来限制

  1. 作用:让样式在局部生效,防止冲突。
  2. 写法:<style scoped>

消息订阅与发布(pubsub)#

也是一种组件间通信的技术,和全局事件总线相似 (任意组件间通信)

使用步骤:

  1. 安装pubsub:npm i pubsub-js

  2. 引入: import pubsub from 'pubsub-js' (发送数据和接收数据的组件都需要引入)

  3. 获取数据的组件 pubsub.subscribe('订阅名',回调函数)

    mounted() {
    // this.pid = pubsub.subscribe('订阅名',回调函数)
    // 回调函数的第一个参数是订阅名,第二个才是数据
    // 和定时器的感觉一样,会返回一个订阅id
    this.pid = pubsub.subscribe('getData', (pbname, data) => {
    console.log(data)
    })
    },
    beforeDestroy() {
    // 取消订阅
    pubsub.unsubscribe(this.pid)
    },
    }
  4. 发送数据的组件: pubsub.publish('xxx',数据)

ref获取Dom和组件实例#

给标签添加的标识,相当于(id的替代)

​ 1.配置ref属性:内置标签 : <h1 ref="xxx"></h1> 组件标签 <School ref="xxx"/>

​ 2.获取Dom和组件实例:this.$refs.xxx 内置标签获取到的是Dom , 组件标签获取到的是组件实例对象

​ 3 .this$refs.xxx获取到组件实例对象,可以直接.方法名()调用该组件的方法

$nextTick#

基本使用#

    1. 语法:this.$nextTick(回调函数)
    2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
    3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。(比如input输入框获取焦点时)

input自动获取焦点#

<template>
<div class="app">
<input v-if="isEdit" ref="inp" type="text" />
<span v-else>点击编辑显示输入框</span>
<button @click="edit">编辑</button>
</div>
</template>
<script>
export default {
data() {
return {
isEdit: false,
}
},
methods: {
edit() {
// 让输入框显示
this.isEdit = true
// 让输入框获取焦点
// this.$refs.inp.focus()//此处报错,因为vue是异步更新DOM,此时无法获取到DOM
this.$nextTick(() => {
// this.$nextTick(回调函数),这里面的回调函数是当DOM更新完才执行
this.$refs.inp.focus()
})
},
},
}
</script>

插槽(父传子,子传父)#

作用:#

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

​ 作用域插槽:父组件 <===> 子组件

分类:#

​ 默认插槽、具名插槽、作用域插槽

使用方式:#

默认插槽:#

​ 只是简单的一处需要插入内容时使用

父组件中:
<Category>
<div>html结构1</div>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot>插槽默认内容...</slot>
</div>
</template>

具名插槽:#

​ 子组件有多处不同需要插入时使用

父组件中:
<Category>
<template slot="head">//写法一
<div>html结构1</div>
</template>
<template v-slot:center>//写法二
<div>html结构2</div>
</template>
<template #footer>//写法三
<div>html结构2</div>
</template>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot name="head">插槽默认内容...</slot>
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>

作用域插槽:#

​ 父组件需要子组件的数据做操作时

基本使用步骤: 1.给 slot 标签,以添加属性的方式传值

<slot :id="item.id" msg="测试文本"></slot>

2.所有添加的属性,都会被收集到一个对象中

{id:3msg:'测试文本'}

3.在template中,通过#插槽名="obj" 接收,默认插槽名为 default

<MyTable :list="list">
<!-- 接收数据 -->
<template #default="obj">
<button @click="del(obj.id)">删除</button>
</template>
</MyTable>

单页面应用程序#

什么是单页面应用程序?#

所有功能在一个html页面上实现

单页面应用优缺点?#

优点:按需更新性能高,开发效率高,用户体验好缺点:学习成本,首屏加载慢,不利于SEO

应用场景?#

系统类网站/内部网站/文档类网站 /移动端站点

Vue封装的过渡与动画#

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

  2. 图示:

  3. 写法:

    1. 准备好样式:

      • 元素进入的样式:
        1. v-enter:进入的起点
        2. v-enter-active:进入过程中
        3. v-enter-to:进入的终点
      • 元素离开的样式:
        1. v-leave:离开的起点
        2. v-leave-active:离开过程中
        3. v-leave-to:离开的终点
    2. 使用<transition>包裹要过度的元素,并配置name属性:

      <transition name="hello">
      <h1 v-show="isShow">你好啊!</h1>
      </transition>
    3. 备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

这篇文章是否对你有帮助?

Vue 工程化与组件通信
作者
蜀枕清何
发布于
2026-02-03
许可协议
CC BY-NC-SA 4.0