【若依】19、Vue3中自定义插件
自定义全局方法
Vue2 中定义全局方法
在 Vue2 中,自定义全局方法的思路如下:
1
Vue.prototype.post = $post
通过 Vue.prototype 将一个方法挂载为全局方法,这样,在具体的 .vue 文件中,我们就可以通过 this 来引用这个全局方法了:
1
2
3
this.$post('/login', this.loginForm).then(res => {
console.log('---', res)
})
在 Vue2 中,我们可以将一个方法挂载为全局方法。 Vue3 这个写法则完全变了:
- 定义的方式变了,不再是 Vue.prototype。
- 引用的方式变了,因为在 Vue3 中,没法直接通过 this 去引用全局方法了。
Vue3 中定义全局方法
首先来看方法定义: ```javascript let app = createApp(App)
/**
- Vue3 中定义全局方法 */ app.config.globalProperties.$sayHello = () => { console.log(‘hello yueyazhui’) }
app.use(store).use(router).mount(‘#app’)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
定义好之后,需要引用,方式如下:
```vue
<template>
<div>
<h1>Hello Vue3</h1>
<div><button @click="handleClick">Click Me</button></div>
</div>
</template>
<script setup>
// getCurrentInstance 方法可以获取到当前的 Vue 对象
import {getCurrentInstance} from 'vue'
// 来自 getCurrentInstance() 方法的 proxy 对象相当于 Vue2 中的 this
const {proxy} = getCurrentInstance()
const handleClick = () => {
proxy.$sayHello()
}
</script>
<style lang='scss' scoped>
</style>
- 首先需要导入 getCurrentInstance() 方法。
- 从第一步导入的方法中,提取出 proxy 对象,这个 proxy 对象就类似于之前在 Vue2 中用的 this。
- 接下来,通过 proxy 对象就可以去引用全局方法了。
其他一些曾经在 Vue2 中使用 this 的地方,现在都可以通过 proxy 来代替了,如:router、store。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<div>
<h1>Hello Vue3</h1>
<h2>Test05</h2>
<div><button @click="handleClick">Click Me</button></div>
<div><button @click="handleGo">Router Demo(Go Test04)</button></div>
<div><button @click="handleChange">Store Demo(Change name)</button></div>
</div>
</template>
<script setup name="Test05">
// getCurrentInstance 方法可以获取到当前的 Vue 对象
import {getCurrentInstance} from 'vue'
// 来自 getCurrentInstance() 方法的 proxy 对象相当于 Vue2 中的 this
const {proxy} = getCurrentInstance()
const handleClick = () => {
proxy.$sayHello()
}
function handleGo() {
proxy.$router.push('/test04')
}
function handleChange() {
console.log(proxy.$store.state.name)
proxy.$store.commit('SET_NAME', '月牙坠')
console.log(proxy.$store.state.name)
}
</script>
<style lang='scss' scoped>
</style>
自定义插件
一些工具方法可以定义为全局方法,如果这个全局的工具,不仅仅是一个工具方法,里边还包含了一些页面等,那么此时,全局方法就不适用了。这个时候我们需要定义插件。 全局方法定义,可以理解为是一个简单的插件。 Vue2 和 Vue3 中自定义插件的流程基本上都差不多,但是,插件内部的钩子函数不一样。
注册全局组件
首先定义一个组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
<div><a href="http://www.yueyazhui.top">月牙坠</a></div>
</div>
</template>
<script setup name="Banner">
</script>
<style lang='scss' scoped>
</style>
接下来,就可以在插件中导入组件并注册:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在这里定义插件
// 在插件中,可以引入 vue 组件,并注册(这里的注册,就相当于全局注册)
import Banner from '@/components/Banner'
export default {
/**
* @param {*} app Vue 对象
* @param {*} options 可选参数
*
* 当项目启动的时候,插件方法就会自动执行
*/
install: (app, options) => {
console.log('这是我的第一个插件', app, options)
// 在这里完成组件的注册,注意,这是一个全局注册
app.component('banner', Banner)
}
}
最后,就可以在项目的任意位置使用这个组件了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- 这里就可以直接使用插件中注册的全局组件了 -->
<banner/>
<router-view/>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
注册全局指令
首先注册全局指令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 在这里定义插件
// 在插件中,可以引入 vue 组件,并注册(这里的注册,就相当于全局注册)
import Banner from '@/components/Banner'
export default {
/**
* @param {*} app Vue 对象
* @param {*} options 可选参数
*
* 当项目启动的时候,插件方法就会自动执行
*/
install: (app, options) => {
console.log('这是我的第一个插件', app, options)
// 在这里完成组件的注册,注意,这是一个全局注册
app.component('banner', Banner)
// 自定义指令
// el 表示添加这个自定义指令的节点
// binding 中包含了自定义指令的参数
app.directive('font-size', (el, binding, vnode) => {
console.log(el, binding, vnode)
let size = 16
// binding.arg 获取到的就是 small 或 large
switch (binding.arg) {
case 'small':
size = 12
break
case 'large':
size = 20
break
default:
break
}
// 为使用 v-font-size 指令的标签设置 font-size 的大小
el.style.fontSize = size + 'px'
})
}
}
然后就可以在任意地方去使用这个全局指令了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<div>
<!-- 使用自定义指令,去指定文本的大小,指令的名字就是 font-size -->
<a href="http://www.yueyazhui.top" v-font-size:small>月牙坠</a>
</div>
<div>
<a href="http://www.yueyazhui.top" v-font-size:large>月</a>
</div>
</div>
</template>
<script setup name="Banner">
</script>
<style lang="scss" scoped>
</style>
参数传递
自定义插件的时候,可以通过 options 传递参数到插件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 在这里定义插件
// 在插件中,可以引入 vue 组件,并注册(这里的注册,就相当于全局注册)
import Banner from '@/components/Banner'
export default {
/**
* @param {*} app Vue 对象
* @param {*} options 可选参数
*
* 当项目启动的时候,插件方法就会自动执行
*/
install: (app, options) => {
console.log('这是我的第一个插件', app, options)
// 在这里完成组件的注册,注意,这是一个全局注册
app.component('banner', Banner)
// 自定义指令
// el 表示添加这个自定义指令的节点
// binding 中包含了自定义指令的参数
app.directive('font-size', (el, binding, vnode) => {
console.log(el, binding, vnode)
let size = 16
// binding.arg 获取到的就是 small 或 large
switch (binding.arg) {
case 'small':
size = options.fontSize.small
break
case 'large':
size = options.fontSize.large
break
default:
break
}
// 为使用 v-font-size 指令的标签设置 font-size 的大小
el.style.fontSize = size + 'px'
})
}
}
options.fontSize.small 就是插件在引用的时候传入的参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 导入插件
import plugins from './plugins'
createApp(App)
.use(plugins, {
fontSize: {
small: 12,
large: 20
}
})
.use(store)
.use(router)
.mount('#app')
provide 和 inject
可以通过 provide 去定义一个方法,然后在需要使用的使用,通过 inject 去注入这个方法然后使用。 方法定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 在这里定义插件
// 在插件中,可以引入 vue 组件,并注册(这里的注册,就相当于全局注册)
import Banner from '@/components/Banner'
export default {
/**
* @param {*} app Vue 对象
* @param {*} options 可选参数
*
* 当项目启动的时候,插件方法就会自动执行
*/
install: (app, options) => {
console.log('这是我的第一个插件', app, options)
// 在这里完成组件的注册,注意,这是一个全局注册
app.component('banner', Banner)
// 自定义指令
// el 表示添加这个自定义指令的节点
// binding 中包含了自定义指令的参数
app.directive('font-size', (el, binding, vnode) => {
console.log(el, binding, vnode)
let size = 16
// binding.arg 获取到的就是 small 或 large
switch (binding.arg) {
case 'small':
size = options.fontSize.small
break
case 'large':
size = options.fontSize.large
break
default:
break
}
// 为使用 v-font-size 指令的标签设置 font-size 的大小
el.style.fontSize = size + 'px'
})
const clickMe = () => {
console.log('------Click Me------')
}
// 提供
app.provide('clickMe', clickMe)
}
}
注意定义的时候,方法要写在 install 中。 方法使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div>
<div>
<!-- 使用自定义指令,去指定文本的大小,指令的名字就是 font-size -->
<a href="http://www.yueyazhui.top" v-font-size:small>月牙坠</a>
</div>
<div>
<a href="http://www.yueyazhui.top" v-font-size:large>月</a>
</div>
</div>
</template>
<script setup name="Banner">
import {inject, onMounted} from 'vue'
onMounted(() => {
// 注入
const clickMe = inject('clickMe')
clickMe()
})
</script>
<style lang="scss" scoped>
</style>
本文由作者按照
CC BY 4.0
进行授权