第一节: 全面细致的理解创建vue3应用的 createApp函数

1. createApp 创建应用


1.1. createApp 函数理解

每个 Vue 应用实例都是通过 createApp 函数创建;每次调用函数都会返回一个新的应用对象;

使用方式

import {createApp} from 'vue'

const app = createApp({
  // ...options
})

通过源码或vue官网, 可以知道createApp函数的类型如下

function createApp(rootComponent: Component, rootProps?: object): App

通过类型可以看出 createApp 接收两个参数:

  1. 第一个参数为根组件对象(可以是.vue单文件组件, 可以是组件对象), 是必传参数,
  2. 第二个参数为传递给根组件的props, 第二个参数时可选参数

createApp 返回一个App 类型的应用对象.如果要详细了解App类型, 可以查看源码. 我们可以通过在控制台输出的方式, 查看返回的应用对象都具有哪些属性.


1.2. 应用对象

createApp函数调用完后返回一个应用对象.

示例:

import {createApp} from 'vue'
const vm =createApp({
})
console.log('vm', vm)

控制台输出结果:

img

通过控制台输出可以看到很多熟悉的单词, 比如component表示组件, directive表示指令, 具体如何使用, 我们娓娓道来

分析完createApp函数的返回值, 接下来我们详细研究一下参数

2. createApp API 参数

createApp函数接受两个参数, 第二个参数是可选地,

第一个参数有两种形式

  1. 直接传入单文件组件, 作为根组件
  2. 使用vue选项对象

2.1. createApp 参数单文件组件

通过createApp函数的类型可知, createApp至少传一个参数, 参数可以为单文件组件

示例:

根组件代码:

<template>
  <div>这是一个新的根组件</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({});
</script>

入口函数main.ts

import { createApp } from 'vue'

// 导入单文件组件
import App from './App.vue'

// 将单文件组件App作为参数传递给createAPP
const app = createApp(App)

运行结果:

img

2.2. createApp 参数组件选项对象

createApp的第一个参数除了可以是单文件组件, 也可以是选项对象

vue2中我们通过template选项添加模板渲染内容

vue3中, 我们也可以使用使用tempate选项定义渲染模板

示例:

// 引入完整vue代码, 包括运行时 + 编译器
import { createApp} from 'vue/dist/vue.esm-bundler.js'


const app = createApp({
  name: 'App',
  // 使用template 模板
  template: `
    <h2>你好,中国</h2>
  `,
})

运行结果:

img

这里有个需要注意的点, 就是导入createApp的模块不是vue, 而是vue/dist/vue.esm-bundler.js

原因在于从vue中导入的模块,是运行时(runtime)代码, 运行时代码不包括编译器(compile), 没有编译器,就不能将模板编译成渲染函数

所以, 如果你需要在组件对象中使用template模板, 一定注意使用完整版vue

因为template模板是需要编译成渲染函数, 通过调用渲染函数, 获取返回的vnode进行页面渲染.

所以我们也可以不使用template选项, 直接编写渲染函数, 渲染函数需要返回vnode.,

vue3提供了一个h函数用于创建vnode, 需要配合setup选项一起使用

示例: 在setup函数中直接返回render渲染函数

import { createApp,h } from 'vue'

// createApp, 组件对象中直接返回渲染函数
const app = createApp({
  name:'App',
  setup(){

    // 返回render渲染函数
    return () => {
      // 渲染中返回vnode, 通过vue3 提供h api 创建vnode
      return h('h1', null, 'hello world')
    }
  }
})

运行结果:

img

这里使用的setup选项, 以及h函数都是vue3开始提供API, 之后我们会详细分析

这里主要记住两点:

  1. setup选项, 可以理解时一个钩子函数, 跟created相似, 会自动执行, 可以直接返回一个渲染函数
  2. h函数用于创建vnode, 渲染函数需要返回vnode

至此, 我们已经分析完createApp函数的第一个参数, 接下来我们分析第二个参数

2.3. createApp 第二个参数为props

createApp函数第二个参数的作用是给根组件传入props数据

props相信大家已经比较熟了, 就是父组件给子组件传参的方式. 问题在于根组件已经是顶级组件了, 没有父组件传入props参数.

此时我们就可以使用createApp第二个参数实现向根组件传参

示例:

import { createApp, h } from 'vue'

const app = createApp(
  // 第一个参数: 根组件对象
  {
    name: 'App',
    // 获取第二个参数传入的props数据
    props: {
      msg: {
        type: String,
        default: ''
      }
    },
    setup(props) {
      console.log('props', props)
  
      return () => h('h1', null, props.msg)
    }
  },

  // 第二个参数: props 对象
  {
    msg: 'hello world'
  }
)

控制台输出的props值:

img

一般情况下使用不到第二个参数, 因为正常使用createApp 时,会使用.vue单文件组件作为参数

而根组件通常是页面的布局结构, 不太能使用到数据

到此为止,createAppAPI 的入参就分析完了, 我们前面讲到过, createApp会返回应用对象.

接下来我们详细分析一下, createApp返回的应用对象

3. 应用对象的属性与方法

前面我们也在控制台输出了createApp函数返回的应用对象.应用对象中具有很多属性和方法.

我们看几个常用的方法

示例: 查看app应用属性与方法

import { createApp } from 'vue'
import App from './App.vue'  // 根组件

// createApp创建app应用实例对象
const app = createApp(App)

console.log(app)
/*

{
	// 1. 注册全局组件
	component:  ƒ component(name, component)
  config: {...}
  directive: ƒ directive(name, directive)
  mixin: ƒ mixin(mixin)

  // 2. 挂载方法(参数时dom对象或选择器)
  mount: (containerOrSelector) => {…}
  provide: ƒ provide(key, value)
  runWithContext: ƒ runWithContext(fn)


  // 3. 卸载应用
  unmount: ƒ ()  
  use: ƒ use(plugin, ...options)
  version: "3.3.4"
  _component: {name: 'JX-APP', __hmrId: 'e16649ff', __scopeId: 'data-v-e16649ff', __file: 'D:/studey/vue-上课/vue3/vue代码/vue3/vue3-studey/src/App2.vue', setup: ƒ, …}
  _container: div#app
  _context: {app: {…}, config: {…}, mixins: Array(0), components: {…}, directives: {…}, …}
  _instance: {uid: 0, vnode: {…}, type: {…}, parent: null, appContext: {…}, …}
  _props: null
  _uid: 0
}

*/

3.1. app.mount 挂载方法

vue3通过调用应用对象的mount()方法挂载应用, 该方法接受一个"容器"参数, 可以是一个真实DOM元素, 也可以是一个选择器字符串


参数为真实dom元素

示例:

import { createApp } from 'vue'
import App from './App.vue'  // 根组件

// createApp创建app应用实例对象
const app = createApp(App)

// 获取真实的dom节点
const dom = document.getElementById('app')

// 通过真实dom节点进行挂载
app.mount(dom)

参数为选择器字符串

示例:

// 导入createApp
import { createApp } from "vue";
import App from "./App.vue";

// 初始化vue应用
const app = createApp(App);

// 调用mount方法挂着vue
app.mount("#app");

这个时候不知道大家是否会有一问, 选择器只能用id吗? 如#app

答案是否定的, 也可以使用其他选择器, 比如class 选择 .app, 只不过id具有唯一性

示例:

<div  class="app"></div>
<script type="module" src="/src/main.ts"></script>s
// 导入createApp
import { createApp } from "vue";
import App from "./App.vue";

// 初始化vue应用
const app = createApp(App);

// 调用mount方法挂着vue
app.mount(".app");

我们会发现也是可以运行的, 原因在于mount参数如果是选择器, vue3会自己获取dom节点

我们不用担心class类名,或者标签名有多个的问题, 因为vue使用querySelector 方法通过选择器获取第一个dom节点

我们简单看一下vue3源码中mount方法的实现

源码:

 app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
   // 获取挂载点的真实dom
    const container = normalizeContainer(containerOrSelector)

   // ....
}


function normalizeContainer(
  container: Element | ShadowRoot | string
): Element | null {
  // 判断mount 挂载方法参数是不是字符串
  if (isString(container)) {
    // 获取dom, 因为使用querySelector 方法获取, 因此返回第一个dom对象
    const res = document.querySelector(container)

    // 如果通过mount参数字符串没有获取到挂载点dom对象, 则报错
    if (__DEV__ && !res) {
      warn(
        `Failed to mount app: mount target selector "${container}" returned null.`
      )
    }
    return res
  }

  
  // 如果参数时真实dom节点直接返回
  return container as any
}

3.2. app.unmount 卸载应用

应用对象通过mount方法挂载元素, 相对应的,是通过unmount方法卸载应用

示例

// 导入createApp
import { createApp } from "vue";
import App from "./App.vue";

// 初始化vue应用
const app = createApp(App);

// 调用mount方法挂着vue
app.mount("#app");


// 卸载应用
app.unmount()

3.3. app.component 注册全局组件

app.component 方法是vue3提供的用于注册全局组件

  1. 如果component方法传入两个参数, 第一个参数为字符串,用于声明组件名称, 第二个参数为组件对象,
  2. 如果component接受一个参数, 参数为一个名字,则会返回用该名字对应的注册组件 (如果存在的话)。

示例:

注册全局组件

// 导入createApp
import { createApp } from "vue";
import App from "./App.vue";

// 初始化vue应用
const app = createApp(App);

// 注册全局组件
app.component(
  // 第一个参数为组件名称
  'jx-hello',
  // 第二参数为组件对象
  {
    name: 'JxHello',
    setup() {
      return () => {
        return h('div', null, '这是一个全局组件')
      }
    }
  }
)


// 调用mount方法挂着vue
app.mount("#app");

使用全局组件

<template>
  <div>
		<!--   使用全局组件     -->
    <jx-hello></jx-hello>
  </div>
</template>


<script  lang="ts">
import { defineComponent,  } from 'vue';


export default defineComponent({
  name: "JX-APP",
  setup() {
    return {}
  }
})
</script>

到这里, createAppAPI的使用就已经分析完了

  • 28
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值