简介
今天又去面试了,问得都是一些比较基础的问题,也都答了个差不多。但是面试官问我:组件库按需加载是如何实现的时候我卡壳了。平时都是使用组件库,具体按需加载原理我也不知道。
然后面试官给我巴拉巴拉讲了好久,大致就是原理好像就是:通过export导出,按需引入使用啥的
。
回来后,我搜了搜,注备写个简单的组件库框架,实现一下这个按需导出,模拟常见组件库的使用
。
项目搭建
如图,创建了两个组件
link组件
和select组件
,分别在两个组件内写好自己的内容。
select组件:
modules\my-ui\Link\index.vue
<template>
<div class="my-select">
<div
class="result"
@click="openOptions"
>{
{
data[curIdx].text }}</div>
<div class="options">
<div
class="option" v-show="optionsShow"
v-for="(item, index) in data"
:key="item.id"
@click="setOption(index, item)"
>{
{
item.text }}</div>
</div>
</div>
</template>
<script>
import {
reactive, toRefs, ref } from "vue"
export default {
name: 'MySelect',
props: {
data:Array,
currentIndex: {
type: Number,
default: 0
},
callback: Function
},
setup(props) {
console.log(props.data)
const state = reactive({
curIdx: props.currentIndex,
optionsShow: false
})
const setOption = (index, item) =>{
state.curIdx = index;
state.optionsShow = false
props.callback(index, item)
}
const openOptions = () => {
state.optionsShow = true
}
return {
...toRefs(state),
setOption,
openOptions
}
}
}
</script>
<style>
</style>
link组件:
modules\my-ui\Link\index.vue
<template>
<a
:href="href"
:target="target"
:class="['my-link', type]"
> <slot></slot></a>
</template>
<script>
import {
reactive, toRefs, ref } from "vue"
export default {
name: 'MyLink',
props: {
href: String,
type: String,
target :String
}
}
</script>
<style lang="scss">
.my-link{
color: #222;
font-size: 14px;
text-decoration: none;
&.primary {
color: blue;
}
&.success {
color: green;
}
}
</style>
将组件导出
在my-ui文件内的index.js中定义相应逻辑
index.js:
modules\my-ui\index.js
import Select from './Select' //同import Select from './Select/index.vue'
import Link from './Link'
const COMPONENTS = [
Select,Link
]
//按需导出部分,可按需引入
export const MySelect = {
}
export const MyLink = {
}
MySelect.install = Vue => Vue.component(Select.name,Select)
MyLink.install = Vue => Vue.component(Link.name,Link)
const MyUI = {
};
//全部导出部分
MyUI.install = function(Vue) {
COMPONENTS.forEach((component) => {
Vue.component(component.name,component)
})
}
export default MyUI
实现原理分析
组件导入
import Select from './Select'; // 同 import Select from './Select/index.vue'
import Link from './Link';
这两行代码导入了两个组件 Select 和 Link。默认情况下,Vue 文件会解析到 ./Select/index.vue 和 ./Link/index.vue。
组件列表
const COMPONENTS = [
Select, Link
];
定义了一个包含所有组件的数组 COMPONENTS,用于后续的全局注册。
按需导出部分
export const MySelect = {};
export const MyLink = {};
MySelect.install = Vue => Vue.component(Select.name, Select);
MyLink.install = Vue => Vue.component(Link.name, Link);
-
- MySelect 和 MyLink 分别作为 Select 和 Link 组件的按需导出对象。
- install 方法将组件注册到 Vue 实例中,Vue.component 方法的第一个参数是组件的名称,第二个参数是组件本身。这样可以通过 Vue.use(MySelect) 或 Vue.use(MyLink) 单独引入组件。
全局导出部分
const MyUI = {};
MyUI.install = function(Vue) {
COMPONENTS.forEach((component) => {
Vue.component(component.name, component);
});
};
export default MyUI;
-
- MyUI 对象包含一个 install 方法,该方法遍历 COMPONENTS 数组,并将所有组件注册到 Vue 实例中。
- 通过 Vue.use(MyUI) 可以一次性引入所有组件,实现全局注册。
引入使用
全局注册
import {
createApp } from 'vue'
import App from './App.vue'
import MyUI from '../modules/my-ui'
createApp(App).use(MyUI).mount('#app')
或
import {
createApp } from 'vue'
import App from './App.vue'
import MyUI from '../modules/my-ui'
const app = createApp(App)
app.use(MyUI)
app.mount('#app')
按需引入
import {
createApp } from 'vue'
import App from './App.vue'
import {
Select } from '../modules/my-ui'
createApp(App).use(Select).mount('#app')
使用demo
App.vue:
<template>
<div>
<my-Select
:data = "data"
:currentIndex = "curIdx"
:callback = "setOption"
/>
<My-Link
href="http://www/baidu.com"
type="primary"
target="_blank"
>百度</My-Link>
<My-Link
href="http://www/baidu.com"
type="success"
target="_blank"
>淘宝</My-Link>
</div>
</template>
<script>
import {
ref } from "vue";
// import MySelect from '../modules/my-ui/Select/index.vue'
// import MyLink from '../modules/my-ui/Link/index.vue'
export default {
name: 'App',
components: {
// MySelect,MyLink
},
setup() {
const curIdx = ref(1)
const data =[
{
id: 1,
value: 'orange',
text: '橘子'
},
{
id: 2,
value: 'apple',
text: '苹果'
},
{
id: 3,
value: 'per',
text: '梨'
}
];
const setOption = (index ,item) =>{
console.log(index,item)
}
return{
data,
curIdx,
setOption
}
}
}
</script>