在写Vue的时候,我们总是会有很多组件,在页面需要的时候就引进了,这时候会有一个问题,就是不同的文件目录下引入文件的路径不同,虽说可以通过alias
配置路径识别符,但是每次都这么频繁引入也是挺麻烦的,尤其是在Vue2里,引入了还要再components里再声明一次。 在Vue技术栈开发过程中,面对复杂项目中的组件复用场景,存在两个显著的工程化痛点:
其一,跨层级模块引用时的路径冗余问题,虽可通过Webpack别名(alias)进行路径映射优化,但在高频组件引用场景下仍存在编码冗余;
其二,在Vue2架构中基于Options API的显式组件注册机制,导致组件管理存在重复声明成本。
一、方法
这种双重约束在大型项目迭代中会显著增加维护复杂度,需通过模块化设计和工程化方案进行系统性优化。有一种比较好解决方法,利用插件
的方式动态导入:
javascript
// 直接引入所有的组件,相当于自己的组件库
import errorTip from './errorTip'
import emailTip from './emailTip'
import steps from './steps'
import confirmPw from './confirmPw'
import accountInput from './accountInput'
import aiInput from './input'
import validateInput from './validateInput'
import graphicalCode from './graphicalCode'
import inviteCode from './inviteCode'
import baValidateInput from './baValidateInput'
import aiButton from './aiButton'
import msgcode from './msgcode'
var Components = {
errorTip,
emailTip,
steps,
confirmPw,
accountInput,
aiInput,
validateInput,
graphicalCode,
inviteCode,
baValidateInput,
aiButton,
msgcode
}
// 插件
var Plugins = {}
export default function install(Vue) {
var componentFlags = Vue.util.mergeOptions(flatObj(Components), flatObj(Plugins))
Vue.mixin({
beforeCreate(){
aicomponentInit.call(this)
}
})
function aicomponentInit() {
var aicomponents = this.$options.aicomponents,
components = [];
if (aicomponents) {
components = aicomponents.forEach((key) => {
var component = componentFlags[key]
if (component) {
inject.call(this, component, key)
return
}
console.warn(`未发现组件:${key}`)
})
}
function inject(component, key) {
key = key.split('_')[0]
if (component.render) {
this.$options.components[key] = Vue.extend(component)
// console.log(component)
} else if (component.install) {
this['$' + key] = component.install(Vue)
// console.log(this['$'+key],'$'+key)
} else {
Object.keys(component).forEach((k) => {
inject.call(this, component[k], k)
})
}
}
}
}
function realComponent(data, k, version, type) {
var temp,
version = version || '',
type = type || ''
if (data[k].render || data[k].install) {
temp = {
name: k,
val: data[k],
version: version,
type: type
}
} else {
type = k.split('_')[0] || '',
version = k.split('_')[1] || ''
temp = Object.keys(data[k]).reduce((arr, key) => {
return arr.concat(realComponent(data[k], key, version, type))
}, [])
}
return temp
}
function flatObj(foldData) {
var content = {}
Object.keys(foldData).reduce(function(arr, k) {
return arr.concat(realComponent(foldData, k))
}, []).forEach(function(item) {
// console.log(item)
if (item.version) {
content[item.type + '_' + item.version] = content[item.type + '_' + item.version] || {}
content[item.type + '_' + item.version][item.name] = item.val
} else {
content[item.name] = item.val
}
})
return content
}
javascript
import components from './components'
import App from './pages/app.vue'
Vue.use(components)
export function render(store,router){
const vue = new Vue({
el:'#app',
store:store,
router:router,
render: h => h(App)
})
}
都做好准备了,看看怎么用:
- 在export中添加了一个aicomponents对象,把需要用到的组件名写进去,比如errorTip;
- 然后在页面中就可以正常使用了;
- 如果有新增一些通用性较小的组件,同样可以像vue原方法那样,写到components中。
xml
<template>
<div>
<errorTip :visible="topError.show" :txt="topError.txt" type="error"></errorTip>
<div class="">
<account-input
ref="account"
fontClass=""
autoComplete="off"
:checkRepeat="false"
@input="account_input"
:account.sync="account"
:valid.sync="accountValid"
></account-input>
</div>
<div class="pt15">
<validateInput
ref="pw"
:isValid.sync="pwValid"
:value.sync="passWord"
:ruleList="pw_rule_list"
autoComplete="off"
placeholder="密码"
></validateInput>
</div>
</div>
</template>
<script>
import bindMobile from './bindMobile.vue';
export default {
aicomponents: ['emailTip', 'errorTip', 'accountInput', 'aiInput', 'validateInput'],
props: {
topError: {
type: Object,
default: () => ({ show: false, txt: '' })
}
},
created() {
// 组件创建
},
data() {
return {
confirm_password_show: false, // 确认密码错误显示
confirm_password_txt: '', // 确认密码错误提示
// 其他数据属性可以在这里添加
};
},
methods: {
loadVerifyCode() {
Service.$model.account.get_verify_code({
captchaType: "RANDOM_LETTER"
}).then((response) => {
this.verify_img_url = "data:image/png;base64," + response.data.image;
this.captchaKey = response.data.captchaKey;
});
},
// 其他方法可以在这里添加
},
components: {
bindMobile
// 其他组件可以在这里添加
}
};
</script>
二、插件式组件的好处
- 无需重复导入 :插件可以一次性全局注册组件,避免在每个使用组件的文件中手动
import
。 - 直接使用标签 :注册后,组件可像原生 HTML 标签一样使用(如
<my-component>
),提升开发效率。 - 统一配置:插件可以集中处理组件的依赖、默认属性或全局逻辑(如国际化、权限控制)
- 注入全局功能:插件不仅能注册组件,还能添加全局方法、指令、混入(mixins)或原型属性。
三、适用场景
- UI 库开发:如按需引入的组件库。
- 功能模块:如全局的权限校验、埋点统计插件。
- 复杂初始化:需要全局配置或依赖注入的组件。
原文连接:用插件的方式注入Vue组件 | 1Z5K