Global API

在vue3 中,将全局改变vue行为的全局API移到由新的createApp方法创建的应用程序实例中,并且它们的影响现在仅限于该应用程序实例

vue2可以改变vue行为的全局API和全局配置

常见的全局API:Vue.component 、Vue.mixin 、Vue.extend、Vue.nextTick
常见的全局配置:Vue.config.silent 、Vue.config.devtools、Vue.config.productionTip

vue2中创建全局组件可以应用在任何vue实例上

<body>
    <div id="app">
        <mycom></mycom>
    </div>
    <div id="app2">
        <mycom></mycom>
    </div>
    <script>
        Vue.component('mycom',{
            template:'<div>我是一个全局组件</div>'
        })
        var vue=new Vue({
            el:'#app'
        })
        var vue2=new Vue({
            el:'#app2'
        })
    </script>
</body>

 

 

 vue2中创建全局指令

<body>
    <input type="text" v-focus>
    <script>
        Vue.directive('focus',{
            inserted:el=>{
                el.focus()
            }
        })
    </script>
</body>

 此时就会自动获取焦点

 

 

像上面的方法都是挂载到Vue的构造函数上面,这样就会导致一些问题:

  • vue2是没有app的概念,通过new Vue()得到的根实例作为app,这样的话所有创建的根实例是共享相同的全局配置,这在测试时会污染其他测试用例,导致测试变得困难
  • 在单页面创建不同全局配置的多个app实例

比如:

<body>
    <div id="app">
        <mycom></mycom>
    </div>
    <div id="app2">
        <mycom></mycom>
    </div>
    <input type="text" v-focus>
    <script>
        Vue.component('mycom',{
            template:'<div>我是一个全局组件</div>'
        })
        Vue.directive('focus',{
            insert:el=>{
                el.focus()
            }
        })
        Vue.mixin({
            mounted:()=>{
                console.log("vue.mixin")
            }
        })
        var vue=new Vue({
            el:'#app'
        })
        var vue2=new Vue({
            el:'#app2'
        })
    </script>
</body>

 如果app和app2它们想有不同的全局配置的话,就会出现问题,比如我们创建的mixin函数此时打开浏览器就会输出

 

 

 它们现在只能拥有共同的全局配置,

vue3引入了应用程序实例 createApp可以很好的解决以上问题

createApp

调用createApp会返回一个应用程序实例,该应用程序实例提供了应用程序上下文,应用程序实例挂载的整个组件树共享相同的应用程序上下文,该上下文提供了先前在vue2中全局的配置

<body>
    <div id="app">{{name}}</div>
    <script>
        var {createApp} =Vue;
        //createApp返回应用程序实例
        var app=createApp({
            data(){
                return {
                    name:'createApp',
                }
            }
        })
        //挂载到app节点
        app.mount("#app")
    </script>
</body>

 

 

 应用实例暴露了 Vue 2 全局 API 的一个子集,经验法则是,任何全局改变 Vue 行为的 API 现在都会移动到应用实例上,以下是 Vue2 全局 API 及其相应的实例 API 列表:

2.x 全局 API3.x 实例 API (app)
Vue.config app.config
Vue.config.productionTip 移除 
Vue.config.ignoredElements app.config.compilerOptions.isCustomElement 
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use 
Vue.prototype app.config.globalProperties
Vue.extend 移除 

配置全局的属性

以axios为例

main.js中配置全局属性

import Axios from 'axios'
import { createApp , } from 'vue'
import App from './App.vue'
const app=createApp(App)
// 配置全局属性
app.config.globalProperties.$http=Axios
app.mount('#app')

 组件中使用全局配置属性

axios.vue

<script>
import { getCurrentInstance, onMounted } from '@vue/runtime-core'
    export default {
        setup(props){
            //在组件中使用全局配置的属性axios,要使用composition api提供的方法,
            //getCurrentInstance用来获取当前组件的实例,然后通过ctx获取当前的上下文
            const{ctx}=getCurrentInstance()
            onMounted(()=>{
                ctx.$http.get('http://jsonplaceholder.typicode.com/posts?userId=2')
                .then(res=>{
                    console.log(res.data)
                })
            })
        }    
    }
</script>

创建自定义组件

import { createApp , h} from 'vue'
import App from './App.vue'
const app=createApp(App)
//创建自定义组件
app.component('my',{
    render:()=>{
        /**
         * h是createElement函数的别名
         * createElement是一个函数,以组件实例为参数进行调用,生成Vnode节点
         * render函数得到这个Vnode节点 之后,返回给Vue的mount函数,渲染成真实DOM节点,并挂载到根节点上
         */
        return h('div','全局自定义组件')
       
    }
})
app.mount('#app')

 在app.vue中引用

<template>
   <div>
   app
   <my></my> 
   </div>
</template>

 

 也可以这样使用,我们定义一个组件muapi.vue,然后再mian.js中引入

import { createApp , h} from 'vue'
import App from './App.vue'
const app=createApp(App)
import muapi  from "./components/muapi.vue"
//创建自定义组件
app.component('my',{
    render:()=>{
        /**
         * h是createElement函数的别名
         * createElement是一个函数,以组件实例为参数进行调用,生成Vnode节点
         * render函数得到这个Vnode节点 之后,返回给Vue的mount函数,渲染成真实DOM节点,并挂载到根节点上
         */
       // return h('div','全局自定义组件')
       return h(muapi)
       
    }
})
app.mount('#app')

 此时就会渲染该组件的内容

 

 在应用之间共享配置

在应用之间共享配置的方法就是创建工厂函数

新建一个fun.vue文件

<template>
    <div>
    <input type="text" v-focus>
    </div>
</template>

 main.js文件

import { createApp , h} from 'vue'
import App from './App.vue'
import fun from "./components/fun.vue"
const app=createApp(App)
app.mount('#app')
const createMy=options=>{
    const app1 =createApp(options) 
    app1.directive('focus',{
        mounted:el=>el.focus()
    })
    return app1 
}
//挂载到app.vue中的#fun上
createMy(fun).mount('#fun')

 app.vue文件

<template>
   <div>
   app
   <div id="fun"></div>
   </div>
</template>

 

 Global和内部API重构可做摇树优化

在vue2中不少global api是作为静态函数直接挂在到构造函数上的,比如Vue.nextTick(),如果从未在代码中用过它们,就会形成所谓的dead code ,这类global api造成的dead code,无法使用webpack的tree sharking排除掉

在vue3做了相应的变化,将他们抽取称为独立的函数,这样打包工具的摇树优化可以将这些dead code排除掉

不会改变vue行为的全局API,现在被成为Global API Treesharking

import {nextTick} from ‘vue’
nextTick(()=>{
  
})

 受影响的api:

  • Vue.nextTick()
  • Vue.observable
  • Vue.version
  • Vue.compile
  • Vue.set    (非兼容)
  • Vue.delete  (非兼容)
posted @ 2021-11-10 10:49  keyeking  阅读(304)  评论(0编辑  收藏  举报