Vue组件(36)尝试一下Vue3的插件

插件

插件是自包含的代码,通常向 Vue 添加全局级功能。它可以是公开 install() 方法的 object,也可以是 function

插件的功能范围没有严格的限制 —— 一般有下面几种:

  • 添加全局方法或者 property。如:vue-custom-element
  • 添加全局资源:指令/过滤器/过渡等。如:vue-touch
  • 通过全局混入来添加一些组件选项。(如vue-router)
  • 添加全局实例方法,通过把它们添加到 config.globalProperties 上实现。
  • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

好吧,上面来自于官网。
简单的说,插件就是一个“高级组件”,或者说是组件的集合,以及专用类库。
其实我们在做工程化开发的时候,就使用了几个插件,比如负责路由的 Vue-Router、负责状态的 Vuex、还有UI库等。

我们可以先看看这几个是怎么实现插件的。

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
import 'dayjs/locale/zh-cn'
import locale from 'element-plus/lib/locale/lang/zh-cn'

createApp(App)
  .use(store)
  .use(router)
  .use(ElementPlus, { locale, size: 'small' })
  .mount('#app')

这是常见的 main.js 函数,创建了几个实例,然后通过 use 挂到 Vue的实例里面。
那么我们写插件的话,也可以模仿一下。

我们先看看 router 、store 是什么样子的。

router

路由

这里的 install 就是 插件需要的函数。

        install(app) {
            const router = this;
            app.component('RouterLink', RouterLink);
            app.component('RouterView', RouterView);
            app.config.globalProperties.$router = router;
            Object.defineProperty(app.config.globalProperties, '$route', {
                get: () => unref(currentRoute),
            });
            // this initial navigation is only necessary on client, on server it doesn't
            // make sense because it will create an extra unnecessary navigation and could
            // lead to problems
            if (isBrowser &&
                // used for the initial navigation client side to avoid pushing
                // multiple times when the router is used in multiple apps
                !started &&
                currentRoute.value === START_LOCATION_NORMALIZED) {
                // see above
                started = true;
                push(routerHistory.location).catch(err => {
                    if ((process.env.NODE_ENV !== 'production'))
                        warn('Unexpected error when starting the router:', err);
                });
            }
            const reactiveRoute = {};
            for (let key in START_LOCATION_NORMALIZED) {
                // @ts-ignore: the key matches
                reactiveRoute[key] = computed(() => currentRoute.value[key]);
            }
            app.provide(routerKey, router);
            app.provide(routeLocationKey, reactive(reactiveRoute));
            app.provide(routerViewLocationKey, currentRoute);
            let unmountApp = app.unmount;
            installedApps.add(app);
            app.unmount = function () {
                installedApps.delete(app);
                if (installedApps.size < 1) {
                    removeHistoryListener();
                    currentRoute.value = START_LOCATION_NORMALIZED;
                    started = false;
                    ready = false;
                }
                unmountApp.call(this, arguments);
            };
            if (((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) && true) {
                addDevtools(app, router, matcher);
            }
        },

好吧,没完全看懂,大概是先注册了两个组件,RouterLink 和 RouterView,这个眼熟吧。
然后判断了一下浏览器的环境。
然后把路由规则注入进来。
最后做销毁。
其他没看懂。

store

状态管理

store 的 install 放在了 prototype 里面。

Store.prototype.install = function install (app, injectKey) {
  app.provide(injectKey || storeKey, this);
  app.config.globalProperties.$store = this;
};

这个比较简单,只做了两件事情,

  • 把 store 通过 provide 注入到根节点。
  • 把 store 挂到 globalProperties 上面。

既然是 用 provide 注入的,那么是不是说可以用 inject 给取出来?

console.log('inject的状态', inject('store'))

真的可以,只是好像也没啥大用。

直接取出来的状态

编写插件

看完了别人的插件,然后自己的插件要如何写呢?

每当这个插件被添加到应用程序中时,如果它是一个对象,就会调用 install 方法。如果它是一个 function,则函数本身将被调用。在这两种情况下——它都会收到两个参数:由 Vue 的 createApp 生成的 app 对象和用户传入的选项。

我们先写一个空的插件体验一下:

./plugins/test-plugin.js

export default {
  install: (app, options) => {
    // Plugin code goes here
    console.log('app', app)
    console.log('options', options)
  }
}

然后在 mian.js 里面挂到实例上面。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
import 'dayjs/locale/zh-cn'
import locale from 'element-plus/lib/locale/lang/zh-cn'

// 测试插件
import testPlugin from './plugins/test-plugin'

createApp(App)
  .use(store)
  .use(router)
  .use(testPlugin, { title: '测试一下插件' })
  .use(ElementPlus, { locale, size: 'small' })
  .mount('#app')

这样我们写的空插件就挂上了,还是老规矩,看看效果。

自己写的空插件
  • option
    这个比较明显了,就是我们在 use 里面传进去的参数,一般可以做默认设置。

  • app
    这个就比较复杂了,属性比较多。

  • app.config.globalProperties
    全局属性,


    globalProperties

路由和状态已经挂上了,还有其他的一些不认识的,也不知道是啥时候挂上去的。

写了这么多好像也没啥实际内容,只是对插件有了一个感性的认知。

后面的基本上就是可以在 install 里面注册插件、注册自定义指令、注入、等等。需要掌握一些基础知识,否则肯定看不懂。

这些还是应该有一个比较实际的例子才会体会的更深刻吧,官网的那个 18n 的例子,我是看的晕晕乎乎的。

我打算写一个自己的状态管理的插件,前面的也构想过一些功能,现在基本了解插件了,打算用插件的形式包装一下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容