重新认识一下 vue3 应用实例

2024-01-07 19:02:32

重新认识一下 vue 应用实例

💕 创建应用实例

每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例

应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串

// main.js
import App from './App.vue'
import { createApp } from 'vue'

const app = createApp(App)
app.mount('#app')

在这里插入图片描述

因此我们可以在入口文件中,通过创建多个 DOM 节点,并在 main.js 文件中创建多个应用实例


💕 app.createApp()、app.createSSRApp()

?createApp: 除了可以传递第一个参数是根组件外,还可以传递第二个参数(可选),它是要传递给根组件的 props

// main.js
import App from './App.vue'
import { createApp } from 'vue'

const app = createApp(App, { msg: '我是通过 createApp 传递给到 根组件 的' })
app.mount('#app')
// App.vue
const props = defineProps({
  msg: {
    type: String
  }
})
onMounted(() => {
 console.log(props.msg) // 我是通过 createApp 传递给到 根组件 的
})

?createSSRApp():以 SSR 激活模式创建一个应用实例。用法与 createApp 完全相同。


💕 app.mount()、app.unmount()

?mount:将应用实例挂载在一个容器元素中。对于每个应用实例,mount 仅能调用一次

参数可以是一个实际的 DOM 元素或一个 CSS 选择器 (使用第一个匹配到的元素)

app.mount('#app')
app.mount(document.body.firstChild) // 挂载到一个实际的 DOM 元素

?unmount:卸载一个已挂载的应用实例。卸载一个应用会触发该应用组件树内所有组件的卸载生命周期钩子

import App from './App.vue'
import { createApp } from 'vue'

const app = createApp(App)
app.mount('#app')

// 2s 后 销毁掉 应用实例
setTimeout(() => {
    app.unmount()
}, 2000)

在组件 HelloWorld 中,当应用挂载完成后,2s 后销毁应用,可以发现其应用组件树内所有组件的卸载生命周期钩子都会触发

<script setup>
import { onBeforeMount, onBeforeUnmount, onMounted, onUnmounted } from 'vue'
onMounted(() => {
  console.log('HelloWorld Mounted')
})
onBeforeMount(() => {
  console.log('HelloWorld BeforeMount')
})
onBeforeUnmount(() => {
  console.log('HelloWorld BeforeUnmount')
})
onUnmounted(() => {
  console.log('HelloWorld UnMounted')
})
</script>

在这里插入图片描述


💕 app.component()

?component:用于全局组件的注册,后续在该应用实例下的所有组件都可以使用该组件,无需再次局部注册

import App from './App.vue'
import { createApp } from 'vue'
import HelloWorld from './components/HelloWorld'
const app = createApp(App)
app.mount('#app')

// 注册全局组件
app.component('HelloWorld', HelloWorld)

但全局注册有以下几个问题:

  • ?如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中(tree-shaking
  • ?在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性

相比之下,局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。

<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
      <HelloWorld />
</template>

💕 app.directive()

? directive:全局注册自定义指令

👨:什么是自定义指令

🧒:利用组件的生命周期钩子函数重用涉及普通元素的底层 DOM 访问的逻辑。vue 提供了内置指令(如:v-modelv-showv-if

在组件中:实现自定义指令

<script setup>
const customFocus = {
  // 组件挂载时,自动获取焦点  
  mounted: (el) => el.focus()
}
</script>
<template>
<input custom-focus />
</template>

全局注册(这里实现一个权限控制的自定义指令)

<button v-auth="['importUser']"></button>
// authBtn.js
import store from '@/store'

function checkPermission (el, binding) {
  // 获取绑定的值,此处为权限 value: ['importUser']
  const { value } = binding
  // 获取所有的功能指令(后端请求回来的数据)
  const points = store.getters.userInfo.permission.points
  // 当传入的指令集为数组时
  if (value && value instanceof Array) {
    // 匹配对应的指令
    const hasPermission = points.some(point => {
      return value.includes(point)
    })
    // 如果无法匹配,则表示当前用户无该指令,那么删除对应的功能按钮
    if (!hasPermission) {
      // 移除节点
      el.parentNode && el.parentNode.removeChild(el)
    }
  } else {
    // eslint-disabled-next-line
    throw new Error('v-permission value is ["admin","editor"]')
  }
}

export default {
  // 在绑定元素的父组件被挂载后调用
  mounted (el, binding) {
    checkPermission(el, binding)
  },
  // 在包含组件的 VNode 及其子组件的 VNode 更新后调用
  update (el, binding) {
    checkPermission(el, binding)
  }
}
// 指令入口文件,将定义的组件进行抛出
import authBtn from './authBtn'
export default app => {
  app.directive('v-auth', authBtn)
}
import App from './App.vue'
import { createApp } from 'vue'
import HelloWorld from './components/HelloWorld'
const app = createApp(App)
app.mount('#app')
// main.js
import installDirective from '@/directives'
installDirective(app)

💕 app.use()

?use:安装一个插件

👨:如何安装一个插件

🧒:安装一个插件的本质是通过传递应用实例对象给到自定义插件中,在插件中针对这个对象进行操作

👨:那它是通过什么方式将应用实例对象进行传入的

🧒:通过 use 方法进行安装,默认会调用插件的 install 方法,有点 component 的使用方式

import App from './App.vue'
import { createApp } from 'vue'
import myPlugin from './plugin'

const app = createApp(App)
// 安装插件
app.use(myPlugin, {
    type: '参数类型',
    msg: '自定义插件'
})

app.mount('#app')
const myPlugin = {
    install: (app, options) => {
        console.log('安装自定义的组件')
        console.log(app, '应用实例对象')
        console.log(options, '配置参数')
        // 进行安装操作。。。。
        // 如挂载一个全局变量,注册全局组件,依赖注入等
    }
}

export default myPlugin

在这里插入图片描述


💕 app.mixin()

?mixin:应用一个全局 mixin (适用于该应用的范围)。一个全局的 mixin 会作用于应用中的每个组件实例。

不推荐

Mixins 在 Vue 3 支持主要是为了向后兼容,因为生态中有许多库使用到。在新的应用中应尽量避免使用 mixin,特别是全局 mixin

// main.js
import App from './App.vue'
import { createApp } from 'vue'
const app = createApp(App)

const myMixin = {
    data() {
        return {
            message: 'Hello World'
        }
    },
    created() {
        console.log('Mixin created');
    },
    methods: {
        someMethod() {
            console.log('Mixin method');
        },
    }
}

// 注入 mixin
app.mixin(myMixin)

app.mount('#app')
<!-- HelloWorld -->
<div>
  {{ message }}
   <button @click="someMethod">测试</button>
</div>
<script>
export default {
    created() {
        console.log('Component created')
    },
    methods: {
      componentMethod() {
        console.log('Component method');
      }
    }
}
</script>

💕 app.provide()

?provide:提供一个值,可以在应用中的所有后代组件中注入使用

import App from './App.vue'
import { createApp } from 'vue'
const app = createApp(App)

// 全局注入
app.provide('msg', 'hello')
app.mount('#app')

在应用的某个组件中:

<!-- HelloWorld -->
<script setup>
import { inject } from 'vue'
const msg = inject('msg')    
</script>
<template>
{{ msg }}
</template>

同理:在某个组件中,也可以通过provide 的方式将变量(方法)进行注入

<script setup>
import { provide } from 'vue'
const location = ref('North Pole')
const updateLocation = () => {
  location.value = 'South Pole'
}
provide('location', {
  location,
  updateLocation
})
</script>
<script setup>
import { inject } from 'vue'

const { location, updateLocation } = inject('location')
</script>

<template>
  <button @click="updateLocation">{{ location }}</button>
</template>

💕 app.runWithContext()

?runWithContext:使用当前应用作为注入上下文执行回调函数(vue3.3 以上)

import { inject } from 'vue'

app.provide('id', 1)

const injected = app.runWithContext(() => {
  return inject('id')
})

console.log(injected) // 1

💕 app.version

?version:提供当前应用所使用的 Vue 版本号

通过判断当前 vue 版本,执行不同的安装插件方式

export default {
  install(app) {
    const version = Number(app.version.split('.')[0])
    if (version < 3) {
      console.warn('This plugin requires Vue 3')
    }
  }
}

💕 app.config.globalProperties

?globalProperties:用于注册能够被应用内所有组件实例访问到的全局属性的对象

app.config.globalProperties.$msg = '123'
<template>
    <HelloWorld :msg="$msg" />
</template>

💕 不常用 app.config.optionMergeStrategies

?optionMergeStrategies:一个用于定义自定义组件选项的合并策略的对象

const app = createApp({
  // 自身的选项
  msg: 'Vue',
  // 来自 mixin 的选项
  mixins: [
    {
      msg: 'Hello '
    }
  ],
  mounted() {
    // 在 this.$options 上暴露被合并的选项
    console.log(this.$options.msg)
  }
})

// 为 `msg` 定义一个合并策略函数
app.config.optionMergeStrategies.msg = (parent, child) => {
  return (parent || '') + (child || '')
}

app.mount('#app')
// 打印 'Hello Vue'

💕 不常用 app.config.errorHandler()

?errorHandler:用于为应用内抛出的未捕获错误指定一个全局处理函数

interface AppConfig {
  errorHandler?: (
    err: unknown, // 错误对象
    instance: ComponentPublicInstance | null, // 触发该错误的组件实例
    info: string // 指出错误来源类型信息的字符串
  ) => void
}

它可以从下面这些来源中捕获错误:

  • 组件渲染器
  • 事件处理器
  • 生命周期钩子
  • setup() 函数
  • 侦听器
  • 自定义指令钩子
  • 过渡 (Transition) 钩子
app.config.errorHandler = (err, instance, info) => {
  console.log(err, 'err')
  console.log(instance, 'instance')
  console.log(info, 'info')
}
<script setup>
const throwError = () => {
  throw new Error('错误信息')
}
</script>
<template>
     <button @click="throwError">抛出错误</button>
</template>

在这里插入图片描述


💕 不常用 app.config.warnHandler()

?warnHandler:用于为 Vue 的运行时警告指定一个自定义处理函数

interface AppConfig {
  warnHandler?: (
    msg: string, // 警告信息
    instance: ComponentPublicInstance | null, // 组件实例
    trace: string // 组件追踪字符串
  ) => void
}

💕 不常用 app.config.performance

?performance:设置此项为 true 可以在浏览器开发工具的“性能/时间线”页中启用对组件初始化、编译、渲染和修补的性能表现追踪。

在这里插入图片描述


💕 不常用 app.config.compilerOptions

? 官方解释

在这里插入图片描述

? 自己的理解:运行编译 vue 文件时,需要调用一些内部内部compilerOptions配置好的方法。我们可以通过修改 compilerOptions 提供的方法,来改写编译过程的一些方法。(不对的话,请多多指教)


💕 不常用 app.config.compilerOptions.isCustomElement()

?isCustomElement:用于指定一个检查方法来识别原生自定义元素

// 将所有标签前缀为 `ion-` 的标签视为自定义元素
app.config.compilerOptions.isCustomElement = (tag) => {
  return tag.startsWith('ion-')
}

💕 不常用 app.config.compilerOptions.whitespace

?whitespace:用于调整模板中空格的处理行为

  • 类型 'condense' | 'preserve'

  • 默认 'condense'

  • 详细信息

    Vue 移除/缩短了模板中的空格以求更高效的模板输出。默认的策略是“缩短”,表现行为如下:

    1. 元素中开头和结尾的空格字符将被缩短为一个空格。
    2. 包含换行的元素之间的空白字符会被删除。
    3. 文本节点中连续的空白字符被缩短成一个空格。

    设置该选项为 'preserve' 则会禁用 (2) 和 (3) 两项。


💕 不常用 app.config.compilerOptions.delimiters

?delimiters:用于调整模板内文本插值的分隔符

  • 类型 [string, string]

  • 默认 ['{{', '}}']

  • 详细信息

    此项通常是为了避免与同样使用 mustache 语法的服务器端框架发生冲突。


💕 不常用 app.config.compilerOptions.comments

?comments:用于调整是否移除模板中的 HTML 注释

  • 详细信息

    默认情况下,Vue 会在生产环境移除所有注释,设置该项为 true 会强制 Vue 在生产环境也保留注释。在开发过程中,注释是始终被保留的。这个选项通常在 Vue 与其他依赖 HTML 注释的库一起使用时使用

文章来源:https://blog.csdn.net/weixin_44659458/article/details/135351412
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。