目录
21、provide(为子孙组件提供数据) 和 inject
1. opstionsAPI 和 compositionAPI的对比
2. 通过hook对compositionAPI中的选项进行抽取(useCounter案例)
4. 获取滚动条位置(useScrollPosition案例)
5. 获取鼠标位置(useMousePosition 案例)
1、reactive API
<template>
<div>
<h2>{{ info.name }} - {{ info.age }}</h2>
<button @click="changeAge">修改age</button>
<h2>{{ reactiveInfo.counter }}</h2>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
const info = reactive({ name: "why", age: 18 });
const changeAge = () => {
info.age++
}
const reactiveInfo = reactive({
counter: 1
})
const increment = () => {
reactiveInfo.counter++;
console.log(reactiveInfo.counter)
}
return {
info,
changeAge,
reactiveInfo,
increment
}
}
}
</script>
2、Ref API
<template>
<div>
<h2>{{ message }}</h2>
<!-- 在template 模板中使用ref 对象,它会自动进行解包 -->
<!-- ref 解包是浅层解包 -->
<h2>当前计数: {{ counter }}</h2>
<!-- 如果外层是reactive包裹的可响应式对象,是可以自动解包的 -->
<h2>{{ reactiveInfo.counter }}</h2>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: {
message: {
type: String,
required: true
}
},
setup() {
// counter 编程一个ref的可响应式的引用
let counter = ref(100);
const reactiveInfo = reactive({
counter
})
const increment = () => {
counter.value++;
console.log(counter.value)
}
return {
counter,
reactiveInfo,
increment
}
}
}
</script>
3、readonly API
<template>
<div>
<button @click="updateState">修改状态</button>
</div>
</template>
<script>
import { reactive , readonly } from 'vue'
export default {
setup() {
// 1. 普通对象
const info1 = { name: "why" };
const readonlyInfo = readonly(info1);
// 2. 响应式对象reactive
const info2 = reactive({
name: "why"
});
const reactiveInfo = readonly(info2);
// 3. 响应式对象ref
const info3 = ref("why");
const refInfo = readonly(info3);
const updateState = () => {
info1.name = "coderwhy"; // 可以修改
info2.name = "coderwhy"; // 可以修改
info3.value = "coderwhy"; // 可以修改
readonlyInfo.name = "coderwhy"; // 只读不可修改
reactiveInfo.name = "coderwhy"; // 只读不可修改
refInfo.value = "coderwhy" // 只读不可修改
}
return {
updateState
}
}
}
</script>
4、isProxy
检查对象是否是由reactive 或 readonly 创建的proxy
5、isReactive
检查对象是否是由reactive 创建的响应式代理
如果该代理是readonly 创建的,但包裹了有reactive 创建的另一个代理,它也会返回true
6、isReadonly
检查对象是否是由readonly 创建的只读代理
7、toRaw
返回reactive 或 readonly 代理的原始对象
8、shallowReactive
创建一个响应式代理,它跟踪其自身property 的响应性,但不执行嵌套对象的深层响应式转换(深层还是原生对象)
9、shallowReadonly
创建一个proxy,使其自身的property 为只读,但不执行嵌套对象的深度只读转换(深层还是可读、可写的)
10、toRefs
<template>
<div>
<h2>{{ name }} - {{ age }}</h2>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
setup() {
const info = reactive({name: "why", age: 18});
//toRefs: 将reactive 对象中的所有属性都转为ref,建立链接
let { name, age } = toRefs(info);
const changeAge = () => {
age.value++;
info.age++;
}
return {
name,
age,
changeAge
}
}
}
</script>
11、toRef
<template>
<div>
<h2>{{ name }} - {{ age }}</h2>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { reactive, toRef } from 'vue'
export default {
setup() {
const info = reactive({name: "why", age: 18});
//toRef: 对其中一个属性进行转换ref,建立链接
let { name } = info;
let age = toRef(info, "age");
const changeAge = () => {
age.value++;
info.age++;
}
return {
name,
age,
changeAge
}
}
}
</script>
12、unref
如果我们想要获取一个ref 引用中的value,那么也可以通过unref 方法
如果参数是一个ref,则返回内部值,否则返回参数本身
这是val = isRef( val ) ? val.value: val 的语法糖函数
13、isRef
判断是否是一个ref 对象
14、shallowRef
创建一个浅层的ref对象
15、triggerRef
手动触发和shallowRef 相关联的副作用
<template>
<div>
<h2>{{ info2 }}</h2>
<button @click="changeInfo2">修改info</button>
</div>
</template>
<script>
import { ref, shallowRef, triggerRef } from 'vue'
export default {
setup() {
// 1.深层响应式
const info1 = ref({ name: "why" })
const changeInfo1 = () => {
info1.value = { name: "james"};
info1.name.value = "james";
}
// 2.浅层响应式
const info2 = shallowRef({ name: "why" })
const changeInfo2 = () => {
info2.name.value = "james"; // 浅层响应式
triggerRef(info2); // 深层响应式
}
return {
info1,
info2,
changeInfo1,
changeInfo2
}
}
}
</script>
16、customRef
创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制
它需要一个工厂函数,该函数接收track 和trigger 函数作为参数
并且应该返回一个带有get 和set 的对象
import { customRef } from 'vue';
// 自定义ref
export default function( value ) {
let timer = null;
return customRef(( track, trigger ) => {
return {
get() {
track(); // 收集依赖
return value;
},
set(newValue) {
// 实现防抖
clearTimeout( timer );
timer = setTimeout(() => {
value = newValue;
trigger(); // 触发更新
},1000)
}
}
})
}
17、computed
<template>
<div>
<h2>{{ firstName }}</h2>
<h2>{{ lastName }}</h2>
<button @click="changeName1">修改firstName</button>
</div>
</template>
<script>
import { ref, computed } from 'vue'
export default {
setup() {
const firstName = ref("Kobe");
const lastName = ref("Bryant");
// fullName 可以展示但不是响应式
const fullName = firstName.value + lastName.value;
// 1. 用法一: 传入一个getter函数
// fullName1 是响应式的
// computed 的返回值是一个ref 对象
const fullName1 = computed(() => { firstName.value + lastName.value})
const changeName1 = () => {
firstName.value = "James"
}
// 2. 用法二:传入一个对象,对象包含getter 和setter
const fullName2 = computed({
get: () => firstName.value + " " + lastName.value,
set(newValue) {
const names = newValue.split(" ");
firstName.value = names[0];
lastName.value = names[1];
}
})
const changeName2 = () => {
fullName2.value = "coder why"
}
return {
firstName,
lastName,
fullName,
fullName1,
fullName2,
changeName1,
changeName2
}
}
}
</script>
18、watchEffect 侦听
1、watchEffect 侦听的基本使用
<template>
<div>
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
const changeName = () => name.value = "kobe";
const changeAge = () => age.value++;
// 会立即执行一次,自动收集内部的可响应式依赖(name.value)
watchEffect(() => {
console.log("name", name.value)
})
return {
name,
age,
changeName,
changeAge
}
}
}
</script>
2、watchEffect 停止侦听
<template>
<div>
<h2>{{ name }} - {{age}}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
// 会立即执行一次,自动收集内部的可响应式依赖(name.value)
const stop = watchEffect(() => {
console.log("name", name.value)
})
const changeName = () => name.value = "kobe";
const changeAge = () => {
age.value++;
if(age.value > 25) {
stop(); // 停止侦听
}
}
return {
name,
age,
changeName,
changeAge
}
}
}
</script>
3、watchEffect 清除副作用
<template>
<div>
<h2>{{ name }} - {{age}}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
// 会立即执行一次,自动收集内部的可响应式依赖(name.value)
const stop = watchEffect((onInvalidate) => {
const timer = setTimeout(() => {
console.log("网络请求成功")
}, 2000)
// 根据name 和age 两个变量发送网络请求
onInvalidate(() => {
// 在这个函数中清除额外的副作用
request.cancel();
clearTimeout(timer);
console.log("onInvalidate")
})
console.log("name", name.value, "age:", age.value)
})
const changeName = () => name.value = "kobe";
const changeAge = () => {
age.value++;
if(age.value > 25) {
stop(); // 停止侦听
}
}
return {
name,
age,
changeName,
changeAge
}
}
}
</script>
19、setup 中使用ref
<template>
<div>
<h2 ref="title">哈哈哈</h2>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const title = ref(null);
// 默认情况下watchEffect 是先立即执行一次的
watchEffect(() => {
console.log(title.value)
},{
// flush: "pre" // 默认情况下watchEffect 是先立即执行一次的
flush: "post" // dom 挂载完之后再执行watchEffect
})
return {
title
}
}
}
</script>
20、生命周期钩子
<template>
<div>
<button @click="increment">{{counter}}</button>
</div>
</template>
<script>
import { onMounted, onUpdated, onUnmounted, ref } from 'vue';
export default {
setup() {
const counter = ref(0);
const increment = () => {
counter.value++
}
onMounted(() => {
console.log("onMounted")
});
onUpdated(() => {
console.log("onMounted")
});
onUnmounted(() => {
console.log("onMounted")
});
return {
counter,
increment
}
}
}
</script>
21、provide(为子孙组件提供数据) 和 inject
// provide.vue
<template>
<div>
<button @click="incrment">+1</button>
<inject/>
</div>
</template>
<script>
import { provide, ref, readonly } from 'vue';
import Inject from './Inject.vue'
export default {
components: {
Inject
},
setup() {
const name = ref("why");
let counter = ref(100);
const increment = () => counter.value++;
// provide(key, value)
// readonly() 子孙组件不能修改数据
provide("name",readonly(name));
provide("counter",readonly(counter));
return {
increment
}
}
}
</script>
// inject.vue
<template>
<div>
<h2>{{ name }} - {{ counter }}</h2>
<button @click="homeIncrement">+1</button>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
setup() {
// inject(key,默认值)
const name = inject("name", "why");
const counter = inject("counter", 18);
const homeIncrement = () => { counter.value++ }
return {
name,
counter,
homeIncrement
}
}
}
</script>
22、compositionAPI 的练习
1. opstionsAPI 和 compositionAPI的对比
// OptionsAPI
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<h2>计数 * 2: {{ doubleCounter }}</h2>
<button @click="incrment">+1</button>
<button @click="decrment">-1</button>
</div>
</template>
<script>
export default {
data() {
return {
counter: 0,
}
},
computed: {
doubleCounter() {
return this.counter * 2;
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter++;
}
}
}
</script>
// CompositionAPI
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<h2>计数 * 2: {{ doubleCounter }}</h2>
<button @click="incrment">+1</button>
<button @click="decrment">--1</button>
</div>
</template>
<script>
import { ref, computed } from 'vue'
export default {
setup() {
const counter = ref(0);
const doubleCounter = computed(() => counter.value * 2);
const increment = () => counter.value++;
const decrement = () => counter.value--;
return {
counter,
doubleCounter,
increment,
decrement
}
}
}
</script>
2. 通过hook对compositionAPI中的选项进行抽取(useCounter案例)
// userCounter.js
import { ref, computed } from 'vue'
export default function() {
const counter = ref(0);
const doubleCounter = computed(() => counter.value * 2);
const increment = () => counter.value++;
const decrement = () => counter.value--;
return {
counter,
doubleCounter,
increment,
decrement
}
}
// App.vue
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<h2>计数 * 2: {{ doubleCounter }}</h2>
<button @click="incrment">+1</button>
<button @click="decrment">--1</button>
</div>
</template>
<script>
import useCounter from './hooks/useCounter'
export default {
setup() {
const { counter, doubleCounter, increment, decrement } = useCounter();
return {
counter,
doubleCounter,
increment,
decrement
}
}
}
</script>
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<h2>计数 * 2: {{ doubleCounter }}</h2>
<button @click="incrment">+1</button>
<button @click="decrment">--1</button>
</div>
</template>
<script>
import useCounter from './hook/useCounter'
export default {
setup() {
return {
...useCounter()
}
}
}
</script>
3. hook 修改title(useTitle案例)
// useTitle.js
import { ref, watch } from 'vue'
export default function(title = "默认的title") {
const titleRef = ref(title);
watch(titleRef, (newValue) => {
document.title = newValue
},{
immediate: true
})
return titleRef
}
//
<template>
<div>
</div>
</template>
<script>
import useTitle from './hooks/useTitle';
export default {
setup() {
const titleRef = useTitle("coder");
setTimeout(() => {
titleRef.value = "123";
}, 1000)
return {
}
}
}
</script>
4. 获取滚动条位置(useScrollPosition案例)
<template>
<div>
<p class="content"></p>
<div class="scroll">
<div class="scroll-x">scrollX: {{ scrollX }} </div>
<div class="scroll-y">scrollY: {{ scrollY }} </div>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const scrollX = ref(0);
const scrollY = ref(0);
document.addEventListener('scroll', () => {
scrollX.value = window.scrollX;
scrollY.value = window.scrollY;
});
return {
scrollX,
scrollY
}
}
}
</script>
<style scoped>
.content {
width: 3000px;
height: 5000px;
}
.scroll {
position: fixed;
right: 30px;
bottom: 30px;
}
</style>>
// useScrollPosition.js
import { ref } from 'vue'
export default function() {
const scrollX = ref(0);
const scrollY = ref(0);
document.addEventListener("scroll", () => {
scrollX.value = window.scrollX;
scrollY.value = window.scrollY;
});
return {
scrollX,
scrollY
}
}
//
<template>
<div>
<p class="content"></p>
<div class="scroll">
<div class="scroll-x">scrollX: {{ scrollX }} </div>
<div class="scroll-y">scrollY: {{ scrollY }} </div>
</div>
</div>
</template>
<script>
import useScrollPosition from './useScrollPosition'
export default {
setup() {
const { scrollX, scrollY } = useScrollPosition();
return {
scrollX,
scrollY
}
}
}
</script>
<style scoped>
.content {
width: 3000px;
height: 5000px;
}
.scroll {
position: fixed;
right: 30px;
bottom: 30px;
}
</style>>
5. 获取鼠标位置(useMousePosition 案例)
// useMousePosition.js
import { ref } from 'vue'
export default function () {
const mouseX = ref(0);
const mouseY = ref(0);
window.addEventListener("mousemove", (event) => {
mouseX.value = event.pageX;
mouseY.value = event.pageY;
});
return {
mouseX,
mouseY
}
}
//
<template>
<div>
<p class="content"></p>
<div class="mouse">
<div class="mouse-x">mouseX: {{ mouseX }} </div>
<div class="mouse-y">mouseY: {{ mouseY }} </div>
</div>
</div>
</template>
<script>
import useMousePosition from './useMousePosition'
export default {
setup() {
const { mouseX, mouseY } = useMousePosition();
return {
mouseX,
mouseY
}
}
}
</script>
<style scoped>
.content {
width: 3000px;
height: 5000px;
}
.mouse {
position: fixed;
right: 30px;
bottom: 30px;
}
</style>>
6. userLocalStorage 案例
// useLocalStorage.js
import { ref, watch } from 'vue'
export default function( key, value ) {
const data = ref(value);
if(value) {
window.localStorage.setItem(key,JSON.stringify(value));
} else {
data.value = JSON.parse(window.localStorage.getItem(key))
}
watch(data, (newValue) => {
window.localStorage.setItem(key, JSON.stringify(newValue));
})
return data;
}
// 一个参数: 取值
const data1 = useLocalStorage("name");
// 两个参数: 保存值
const data2 = useLocalStorage("name","coderWhy");
//
<template>
<div>
<h2>{{ data }}</h2>
<button @click="changeData">修改data</button>
</div>
</template>
<script>
import useLocalStorage from './useLocalStorage';
export default {
setup() {
const data = useLocalStorage("info", { name: "coder", age: 18 });
const changeData = () => data.value = "哈哈哈";
return {
data,
changeData
}
}
}
</script>
23、setup 顶层编写方式
// 父组件
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<hello-world message="呵呵呵" @increment="getCounter"></hello-world>
</div>
</template>
<script setup>
import { ref } from 'vue';
import HelloWorld from './HelloWorld.vue';
const counter = ref(0);
const increment = () => counter.value++;
const getCounter = (payload) => {
console.log(payload);
};
</script>
// 子组件
<template>
<div>
<h2>Hello World</h2>
<h2>{{ message }}</h2>
<button @click="emitEvent">发射事件</button>
</div>
</template>
<script setup>
import { defineProps, defineEmit } from 'vue';
const props = defineProps({
message: {
type: String,
define: "哈哈哈"
}
})
const emit = defineEmit(["increment"]);
const emitEvent = () => {
emit("increment","10000");
}
</script>
24、h 函数
h() 函数式一个用于创建vnode 的一个函数,更准确的命名是createVNode() 函数
h() 函数有三个参数:(标签名称 | 组件,第一个参数中有哪些属性,子元素 | 子组件)
1. render函数 和 h函数的使用
<script>
import { h } from 'vue'
export default {
render() {
return h("h2",{ class: "title" },"Hello Render");
}
}
</script>
2. 通过render函数实现计数器
<script>
import { h } from 'vue'
export default {
data() {
return {
counter: 0
}
},
render() {
return h("div",{ class: "app" },[
h("h2",null,`当前计数: ${this.counter}`),
h("button",{
onClick: () => this.counter++
},"+1"),
h("button",{
onClick: () => this.counter--
},"-1")
]);
}
}
</script>
<script>
import { h, ref } from 'vue'
export default {
setup() {
const counter = ref(0);
return () => {
return h("div",{ class: "app" },[
h("h2",null,`当前计数: ${counter.value}`),
h("button",{
onClick: () => counter.value++
},"+1"),
h("button",{
onClick: () => counter.value--
},"-1")
]);
}
},
}
</script>
3. render 函数中组件和插槽的使用
//App.vue 父
<script>
import { h, ref } from 'vue'
import HelloWorld from './HelloWorld.vue'
export default {
render() {
return h(HelloWorld, null, {
default: props => h("span", null, `app传入到HelloWorld中的内容: ${props.name}`)
})
}
}
</script>
//HelloWorld.vue
<script>
import { h } from 'vue'
export default {
render() {
return h("div", null, [
h("h2", null, "Hello World"),
this.$slots.default ? this.$slots.default({name: "coder"}) : h("span", null, "我是Hello World的默认值")
])
}
}
</script>
25、jsx的使用
// App.vue
<script>
import HelloWorld from './HelloWorld.vue'
export default {
data() {
return {
counter: 0
}
},
render() {
const increment = () => this.counter++;
const decrement = () => this.counter--;
return (
<div>
<h2>当前计数: { this.counter }</h2>
<button onClick={ increment }>+1</button>
<button onClick={ decrement }>-1</button>
<HelloWorld>
{{default: props => <button>我是按钮</button>}}
</HelloWorld>
</div>
)
}
}
</script>
// HelloWorld.vue
<script>
export default {
render() {
return (
<div>
<h2>HelloWorld</h2>
{ this.$slots.default ? this.$slots.default() : <span>哈哈</span>}
</div>
)
}
}
</script>
25、自定义指令
一、案例:当某个元素挂载完成后可以自动获取焦点
// 默认的实现方式
<template>
<div>
<input type="text" ref="input">
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const input = ref(null);
onMounted(() => {
console.log(input.value);
input.value.focus();
})
return {
input
}
}
}
</script>
// 局部指令
<template>
<div>
<input type="text" v-focus>
</div>
</template>
<script>
export default {
// 局部指令
directives: {
focus: {
mounted(el, bindings, vnone, preVnode) {
console.log("focus");
el.focus();
}
}
},
}
</script>
// 全局定义自定义指令
const app = createApp(App);
app.directive("focus", {
mounted(el, bindings, vnone, preVnode) {
console.log("focus");
el.focus();
}
});
app.mounted('#app');
二、指令的生命周期
<template>
<div>
<button v-if="counter < 2" v-why @click="increment">当前计数: {{ counter }}</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const counter = ref(0);
const increment = () => counter.value++;
return {
counter,
increment
}
},
directives: {
why: {
created(el, bindings, vnode, preVnode) {
console.log("created");
},
beforeMounted(el, bindings, vnode, preVnode) {
console.log("beforeMounted");
},
mounted(el, bindings, vnode, preVnode) {
console.log("mounted");
},
beforeUpdate(el, bindings, vnode, preVnode) {
console.log("beforeUpdate");
},
updated(el, bindings, vnode, preVnode) {
console.log("updated");
},
beforeUnmounted(el, bindings, vnode, preVnode) {
console.log("beforeUnmounted");
},
unmounted(el, bindings, vnode, preVnode) {
console.log("unmounted");
}
}
}
}
</script>
三、自定义指令的参数和修饰符
<template>
<div>
<button v-if="counter < 2" v-why.aaa.bbb="'coderWhy'" @click="increment">当前计数: {{ counter }}</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const counter = ref(0);
const increment = () => counter.value++;
return {
counter,
increment
}
},
directives: {
why: {
// el 表示dom元素, bindings 表示自定义指令的修饰符和参数
created(el, bindings, vnode, preVnode) {
console.log("created");
console.log(bindings.value); // coderWhy
console.log(bindings.modifiers); // {aaa: true, bbb: true}
}
}
}
}
</script>
四、hook 方式注册全局自定义指令
// main.js
import registerDirectives from './index.js'
registerDirectives (app);
// App.vue
<template>
<div>
<h2 v-format-time="YYYY/MM/DD">{{ timeStamp }}</h2>
</div>
</template>
<script>
export default {
setup() {
const timeStamp = 1624452193;
return {
timeStamp
}
}
}
</script>
// index.js
import registerFormatTime from 'format-time.js';
export default function registerDirectives(app) {
registerFormatTime(app);
}
// format-time.js
import dayjs from 'dayjs';
export default function() {
let formatString = "YYYY-MM-DD HH:mm:ss";
app.directive("format-time", {
created(el, bindings) {
if(bindings.value) {
formatString = bindings.value;
}
},
mounted(el, bindings) {
const textContent = el.textContent;
let timestamp = parseInt(textContent);
if( textContent.length === 10 ) {
textContent = textContent * 1000;
}
el.textContent = dayjs(timestamp).format(formatString);
}
})
}
26、Vue 的插件 plugins
一、对象方式书写插件
// plugin_object.js
export default {
install(app) {
console.log(app);
app.config.globalProperties.$name = "coder";
}
}
// main.js
import pluginObject from './plugins_object';
app.use(pluginObject);
// App.vue
<script>
import { getCurrentInstance } from 'vue';
export default {
// 1. composition_API写法
setup() {
const instance = getCurrentInstance();
console.log(instance.appContext.config.globalProperties.$name);
},
// 2. options_API 写法
mounted() {
console.log(this.$name);
}
}
</script>
二、函数方式书写插件
// plugin_function.js
export default function(app) {
console.log(app);
app.config.globalProperties.$name = "coder";
}
// main.js
import pluginFunction from './plugins_function';
app.use(pluginFunction);
// App.vue
<script>
import { getCurrentInstance } from 'vue';
export default {
// 1. composition_API写法
setup() {
const instance = getCurrentInstance();
console.log(instance.appContext.config.globalProperties.$name);
},
// 2. options_API 写法
mounted() {
console.log(this.$name);
}
}
</script>