1. createApp 创建应用
1.1. createApp 函数理解
每个 Vue 应用实例都是通过 createApp
函数创建;每次调用函数都会返回一个新的应用对象;
使用方式
javascript
import {createApp} from 'vue'
const app = createApp({
// ...options
})
通过源码或vue
官网, 可以知道createApp
函数的类型如下
php
function createApp(rootComponent: Component, rootProps?: object): App
通过类型可以看出 createApp
接收两个参数:
- 第一个参数为根组件对象(可以是
.vue
单文件组件, 可以是组件对象), 是必传参数, - 第二个参数为传递给根组件的
props
, 第二个参数时可选参数
createApp
返回一个App
类型的应用对象.如果要详细了解App
类型, 可以查看源码. 我们可以通过在控制台输出的方式, 查看返回的应用对象都具有哪些属性.
1.2. 应用对象
createApp
函数调用完后返回一个应用对象.
示例:
javascript
import {createApp} from 'vue'
const vm =createApp({
})
console.log('vm', vm)
控制台输出结果:
通过控制台输出可以看到很多熟悉的单词, 比如component
表示组件, directive
表示指令, 具体如何使用, 我们娓娓道来
分析完createApp
函数的返回值, 接下来我们详细研究一下参数
2. createApp API 参数
createApp
函数接受两个参数, 第二个参数是可选地,
第一个参数有两种形式
- 直接传入单文件组件, 作为根组件
- 使用
vue
选项对象
2.1. createApp 参数单文件组件
通过createApp
函数的类型可知, createApp
至少传一个参数, 参数可以为单文件组件
示例:
根组件代码:
xml
<template>
<div>这是一个新的根组件</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({});
</script>
入口函数main.ts
javascript
import { createApp } from 'vue'
// 导入单文件组件
import App from './App.vue'
// 将单文件组件App作为参数传递给createAPP
const app = createApp(App)
运行结果:
2.2. createApp 参数组件选项对象
createApp
的第一个参数除了可以是单文件组件, 也可以是选项对象
在vue2
中我们通过template
选项添加模板渲染内容
在vue3
中, 我们也可以使用使用tempate
选项定义渲染模板
示例:
javascript
// 引入完整vue代码, 包括运行时 + 编译器
import { createApp} from 'vue/dist/vue.esm-bundler.js'
const app = createApp({
name: 'App',
// 使用template 模板
template: `
<h2>你好,中国</h2>
`,
})
运行结果:
这里有个需要注意的点, 就是导入createApp
的模块不是vue
, 而是vue/dist/vue.esm-bundler.js
原因在于从vue
中导入的模块,是运行时(runtime)
代码, 运行时代码不包括编译器(compile)
, 没有编译器,就不能将模板编译成渲染函数
所以, 如果你需要在组件对象中使用template
模板, 一定注意使用完整版vue
因为template
模板是需要编译成渲染函数, 通过调用渲染函数, 获取返回的vnode
进行页面渲染.
所以我们也可以不使用template
选项, 直接编写渲染函数, 渲染函数需要返回vnode
.,
vue3
提供了一个h
函数用于创建vnode
, 需要配合setup
选项一起使用
示例: 在setup
函数中直接返回render渲染函数
javascript
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')
}
}
})
运行结果:
这里使用的setup
选项, 以及h
函数都是vue3
开始提供API, 之后我们会详细分析
这里主要记住两点:
setup
选项, 可以理解时一个钩子函数, 跟created
相似, 会自动执行, 可以直接返回一个渲染函数h
函数用于创建vnode
, 渲染函数需要返回vnode
至此, 我们已经分析完createApp
函数的第一个参数, 接下来我们分析第二个参数
2.3. createApp 第二个参数为props
createApp
函数第二个参数的作用是给根组件传入props
数据
props
相信大家已经比较熟了, 就是父组件给子组件传参的方式. 问题在于根组件已经是顶级组件了, 没有父组件传入props
参数.
此时我们就可以使用createApp
第二个参数实现向根组件传参
示例:
javascript
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
值:
一般情况下使用不到第二个参数, 因为正常使用createApp
时,会使用.vue
单文件组件作为参数
而根组件通常是页面的布局结构, 不太能使用到数据
到此为止,createApp
API 的入参就分析完了, 我们前面讲到过, createApp
会返回应用对象.
接下来我们详细分析一下, createApp
返回的应用对象
3. 应用对象的属性与方法
前面我们也在控制台输出了createApp
函数返回的应用对象.应用对象中具有很多属性和方法.
我们看几个常用的方法
示例: 查看app应用属性与方法
yaml
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元素
示例:
javascript
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)
参数为选择器字符串
示例:
javascript
// 导入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
具有唯一性
示例:
xml
<div class="app"></div>
<script type="module" src="/src/main.ts"></script>s
javascript
// 导入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
方法的实现
源码:
dart
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
方法卸载应用
示例
javascript
// 导入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
提供的用于注册全局组件
- 如果
component
方法传入两个参数, 第一个参数为字符串
,用于声明组件名称, 第二个参数为组件对象, - 如果
component
接受一个参数, 参数为一个名字,则会返回用该名字对应的注册组件 (如果存在的话)。
示例:
注册全局组件
javascript
// 导入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");
使用全局组件
xml
<template>
<div>
<!-- 使用全局组件 -->
<jx-hello></jx-hello>
</div>
</template>
<script lang="ts">
import { defineComponent, } from 'vue';
export default defineComponent({
name: "JX-APP",
setup() {
return {}
}
})
</script>
到这里, createApp
API的使用就已经分析完了