一、项目结构与完整代码
首先梳理项目结构(基于 Vue-cli 初始化的基础结构),确保代码文件对应清晰:
src/
├─ components/ # 组件目录
│ ├─ Student.vue # 学生组件(props演示)
│ ├─ Mixin1.vue # 混入演示组件1
│ └─ Mixin2.vue # 混入演示组件2
├─ mixin.js # 混入文件(代码复用)
├─ plugins.js # 插件文件(全局功能)
├─ App.vue # 根组件(整合所有特性)
└─ main.js # 入口文件(初始化Vue、引入插件)
1. src/mixin.js(混入文件:代码复用)
/*
编写混合
这里用分别暴露
mixin混入:
对于data中的数据及methods方法:若原来的组件有用原来的,没有则混合加入
对于钩子函数:先执行混合里的。再执行组件自己的
*/
export const mixin = {
data() {
return {
x:100
}
},
methods:{
show(){
alert(this.name)
},
},
mounted() {
console.log('挂载完毕')
},
}
2. src/plugins.js(插件文件:全局功能扩展)
/*
Vue插件:本质是包含install方法的对象,用于扩展Vue全局功能
install方法参数:
- Vue:Vue构造函数(固定第一个参数)
- options:Vue.use(plugin, options)传递的额外参数(可选)
*/
export default{
install(Vue,args){ //args参数可省略
//定义全局过滤器 Vue.filter()
//定义全局指令Vue.directive()
//定义全局混入Vue.mixin()
//定义全局方法
Vue.prototype.hello = (msg)=>{alert(msg)}
}
}
3. src/components/Student.vue(props 演示:父子通信)
<template>
<div>
<h1>{{ msg }}</h1>
<h1>姓名:{{ name }}</h1>
<h1>年龄{{ age+1 }}</h1>
</div>
</template>
<script>
export default {
name:"Student",
data() {
return {
msg:'北京大学',
}
},
//props作用:让组件可以接受外部传入的数据。props中的内容会出现在vc身上
// 写法1:表示可以在使用该组件时传入age,name参数。*用得多*
props:['age','name'],
/*
写法2:限定参数类型。不符合控制台会给警告
props:{
name:String,
age:Number
}
写法3:
props:{
name:{
type:String,
required:true //引用该组件必须要传入name,不传控制台会给警告。required和default不共存,没意义
},
age:{
type:Number,
default:99 //默认值
}
}
*/
/*
props中的属性不建议修改,会有警告。因为Vue框架设计的核心之一是单向数据流,即数据从父组件流向子组件,并通过props传递。这便于调试
<input type="button" value="age++" @click="age++"/>
若有改的业务,解决方法:
data(){
return{
//让myAge来进行状态管理
myAge:this.age //这里的this.age来源于props。说明先加载props再加载data
}
}
*/
}
</script>
<style>
</style>
4. src/components/Mixin1.vue(混入演示 1)
<template>
<div>
<h1 @click="show">点我显示name1</h1>
</div>
</template>
<script>
import {mixin} from '../mixin'
export default {
data() {
return {
name:'name1'
}
},
//引入了mixin中的methos,data,amounted
mixins:[
mixin
],
/*
methods:{
show(){
alert(this.name)
}
}
*/
}
</script>
<style>
</style>
5. src/components/Mixin2.vue(混入演示 2)
<template>
<div>
<h1 @click="show">点我显示name2</h1>
</div>
</template>
<script>
import {mixin} from '../mixin'
export default {
data() {
return {
name:'name2'
}
},
//引入了mixin中的methos,data,amounted
mixins:[
mixin
]
/*
methods:{
show(){
alert(this.name)
}
}
*/
}
</script>
<style>
</style>
6. src/App.vue(根组件:整合所有特性)
<template>
<div>
<!--
知识点1:ref引用
ref引用的对象会出现在vc的$refs属性上,可用于获取dom对象或vc对象。获取方式:this.$refs.xxx
-->
<h1 ref="h">呵呵哒</h1>
<input type="button" @click="show" value="获取dom对象"/>
<input type="button" @click="showVC" value="获取vc对象"/>
<hr>
<!--
知识点2:props传参
:age和age写法都行。:age表示引号里当作表达式,因此这里的18传递的是数字类型
-->
<Student :age="18" name="张三" ref="student"></Student>
<Student age="18" name="李四"></Student>
<hr>
<!--
知识点3:mixins混入
-->
<Mixin1></Mixin1>
<Mixin2></Mixin2>
<hr>
<!--
知识点4:plugins插件
-->
<input type="button" @click="hello('你好')" value="调用全局方法" />
</div>
</template>
<script>
import Student from './components/Student.vue'
import Mixin1 from './components/Mixin1.vue'
import Mixin2 from './components/Mixin2.vue'
export default {
name:'App',
data() {
return {
}
},
components:{
Student,
Mixin1,
Mixin2
},
methods:{
show(){
console.log(this.$refs.h)
},
showVC(){
console.log(this.$refs.student)
//父子可以交互数据了:this.$refs.student.msg = '呵呵哒'
}
}
}
</script>
<style>
</style>
7. src/main.js(入口文件:初始化 Vue、引入插件)
import Vue from 'vue'
import App from './App.vue'
/*
全局混合:
import {mixin} from './mixin'
Vue.mixin(mixin)
*/
import plugins from './plugins'
//Vue.use本质会执行插件的install方法
//Vue.use(plugins) 无参引入插件
Vue.use(plugins,'参数')//有参引入插件
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
二、核心知识点解析
1. props:父子组件通信
(1)什么是 props?
props
是 Vue 中父组件向子组件传递数据的单向数据流机制,子组件通过props
接收父组件的数据,且数据会挂载到子组件实例(vc
)上,可直接在模板或逻辑中使用。
(2)props 的 3 种写法(按场景选择)
写法 | 语法示例 | 适用场景 | 特点 |
---|---|---|---|
基础写法 | props: ['age', 'name'] | 简单场景(无需校验) | 简洁,无类型 / 必填校验 |
类型校验 | props: { name: String, age: Number } | 需要确保数据类型 | 不符合类型会触发警告 |
完整配置 | props: { name: { type: String, required: true } } | 复杂场景(需校验 + 默认值) | 支持类型、必填、默认值、自定义验证 |
(3)关键注意事项:单向数据流
- 为什么不能直接修改 props?
Vue 设计props
为单向数据流(父→子),目的是保证数据来源唯一,便于调试(避免子组件修改父组件数据导致的混乱)。直接修改props
会触发控制台警告。 - 正确修改方案:
子组件用自身data
接收props
(如myAge: this.age
),后续修改myAge
,不影响父组件的原始数据。
2. ref:获取 DOM 与组件实例
(1)什么是 ref?
ref
是 Vue 提供的用于标记 DOM 元素或组件实例的属性,通过this.$refs.xxx
可快速获取标记的元素或实例,避免手动操作document.querySelector
。
(2)ref 的 2 种常用场景
-
获取 DOM 元素:
给 DOM 元素加ref="xxx"
,通过this.$refs.xxx
获取原生 DOM 对象,可直接操作 DOM(如修改样式、获取内容)。
示例:this.$refs.titleDom.style.color = 'red'
-
获取组件实例:
给子组件加ref="xxx"
,通过this.$refs.xxx
获取子组件实例(vc
),可访问子组件的data
、methods
,实现父子组件交互。
示例:this.$refs.studentRef.myAge = 25
(修改子组件数据)
(3)注意事项
ref
获取时机:需在组件mounted
钩子后获取(DOM 未挂载时this.$refs.xxx
为undefined
)。- 避免过度使用:优先通过数据驱动(如
v-if
、v-for
)操作 DOM,ref
仅在必要时使用(如复杂 DOM 操作、组件交互)。
3. mixin:组件代码复用
(1)什么是 mixin?
mixin
(混入)是 Vue 中提取多个组件公共代码(数据、方法、钩子函数)的机制,避免重复编写相同逻辑,提高代码复用率。
(2)mixin 的 2 种使用方式
-
局部混入:仅当前组件使用,通过
mixins: [mixin1, mixin2]
引入(支持多个混入)。
示例:Mixin1.vue 和 Mixin2.vue 引入mixin
,复用show
方法和x
数据。 -
全局混入:所有组件都会继承,通过
Vue.mixin(mixin)
注册(谨慎使用,避免污染全局)。
示例:main.js 中注释的Vue.mixin(mixin)
,全局混入后所有组件都有x
数据和show
方法。
(3)mixin 的优先级规则(关键)
- 数据(data)和方法(methods):组件自身的优先级高于混入(组件有则用组件的,无则用混入的)。
例:若组件和混入都有show
方法,执行组件的show
。 - 钩子函数(如 mounted):混入的钩子先执行,组件的钩子后执行(两者都会执行,不覆盖)。
例:mixin 的mounted
先打印,再打印 Mixin1/Mixin2 的mounted
。
4. plugin:Vue 全局功能扩展
(1)什么是 plugin?
plugin
(插件)是 Vue 中扩展全局功能的机制,本质是包含install
方法的对象,可用于注册全局方法、过滤器、指令、混入等,一次注册,全项目可用。
(2)插件的核心流程
-
定义插件:必须包含
install
方法,第一个参数是Vue
构造函数,后续参数是Vue.use
传递的额外参数。
示例:plugins.js 中install
方法挂载全局方法hello
。 -
使用插件:通过
Vue.use(plugin, options)
注册,Vue
会自动调用插件的install
方法。
示例:main.js 中Vue.use(plugins, '插件初始化参数')
,传递参数并初始化插件。 -
调用全局功能:插件挂载的全局方法(如
this.hello
)可在所有组件中通过this
调用。
示例:App.vue 中this.hello('内容')
调用全局方法。
(3)插件的常见用途
- 注册全局方法(如接口请求方法
this.$http
)。 - 注册全局过滤器(如日期格式化
{{ time | dateFormat }}
)。 - 注册全局指令(如自动聚焦
v-focus
)。 - 注入全局混入(如全局权限校验)。
三、总结
特性 | 核心作用 | 应用场景 | 注意事项 |
---|---|---|---|
props | 父子组件通信(父→子) | 父组件向子组件传递数据 | 单向数据流,不直接修改 props |
ref | 获取 DOM / 组件实例 | 复杂 DOM 操作、父子组件交互 | 挂载后获取,避免过度使用 |
mixin | 组件代码复用 | 多个组件有相同数据 / 方法 / 钩子 | 注意优先级,避免全局混入污染 |
plugin | 全局功能扩展 | 全局方法、过滤器、指令 | 必须包含 install 方法 |