installation
Stand-alone installation
You can download the latest version directly from the official website of Vue.js and import it with the script tag
CDN installation
Directly use script to introduce <script src="https://unpkg.com/vue@next"></script>
npm installation
npm version must be greater than 3.0
npm install vue@next
Command line tools:
The package name has changed from the previous version, from vue-cli to @vue/cli. If you have previously installed vue-cli1.x or vue-cli2.x globally. First needUse the command
npm uninstall vue-cli -g
oryarn global remove vue-cli
uninstall the previous version and install itNote for Node version:
Vue CLI 4.x requires NodeJs version >=8.9
npm install -g @vue/cli
or
yarn global add @vue/cli
Note: vue-cli 3.x and vue-cli 2.x use the same vue command. If you have installed vue-cli 2.x before, it will be replaced with Vue-cli 3.x. Install @vue/cli-int:
npm i -g @vue/cli-init
Create project
Vue CLI
Use the command vue create project name to create the project
Then wait for the corresponding template and dependencies to be downloaded.
run :
cd project name
npm run serve
Vite
Vite is a web development and construction tool. Thanks to its native ES module import method, it can achieve lightning-like cold server startup.
You can use Vite to quickly build Vue projects by running the following commands in the terminal.
Install create-vite-app globally:
npm i -g create-vite-app
Create project:
npm init vite-app <项目名>
run:
cd project name
npm install
npm run dev
Vue3 directory structure
Command line tool @vue/cli
Directory analysis
Catalog file | Description |
---|---|
public | Public resource directory |
src | Here is the directory we want to develop, basically everything we need to do is in this directory |
.xxxx file | These are some configuration files, including syntax configuration, git configuration, etc. |
package.json | Project configuration file |
README.md | Project documentation, markdown format |
Vue3- basic points
Get started
All the notes below are based on the @vue/cli method to create a project for explanation
Composition API
Why do you need Composition API
Composition API is the biggest feature of Vue3, and it can also be clearly seen that it is inspired by React Hooks
- Solve the problem that the readability of the code becomes worse as the component becomes larger
- Every way of code reuse has flaws
- TS support is limited
setup
setup is a newly added option in Vue3.x, it is the entrance Composition API
Timing of setup execution
Based on a comparison VueJs life cycle, found setup
earlier than beforeCreate
execution .
<script>
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
setup() {
console.log('setup')
},
})
</script>
setup parameters
When using setup
, it accepts two parameters:
{Data} props
{SetupContext} context
props
accepted in setup is responsive and will be updated in time when new props are passed in. Because it is responsive, cannot use ES6 to deconstruct . Deconstruction will eliminate its responsiveness. Error code example:
<script>
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
setup(props) {
const { name } = props
console.log('prop name', name)
},
})
</script>
Getting a value from the
props in root scope of
setup() will cause the value to lose reactivity vue/no-setup-props-destructure
setup type
interface Data {
[key: string]: unknown
}
interface SetupContext {
attrs: Data
slots: Slots
emit: (event: string, ...args: unknown[]) => void
}
function setup(props: Data, context: SetupContext): Data
As can be seen from the two interfaces defined by ts above, the second parameter context
setup
function has three attributes, namely:
- attrs: corresponding to the attribute
$attr
- slots: corresponding to the
slot
slot in vue2.x - emit: corresponds to the
$emit
sending event in vue2.x
The purpose of this design is that we cannot access this
setup
function. And these attributes are automatically synchronized with the latest value, so we get the latest value every time we use it.
Life cycle
Change the source of the picture, other bloggers
The life cycle hook function can be registered by directly importing the onX
<script>
import { defineComponent, onMounted, onUpdated, onUnmounted } from 'vue'
export default defineComponent({
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
})
</script>
These lifecycle hook functions setup
function, because they rely on the internal global state to locate the current active instance (the component instance of setup
Calling them without the currently active instance will cause an error.
The component instance context is also set during the synchronous execution of the life cycle hook. When the component is uninstalled, the observation program watch
and the calculated attribute computed
created synchronously in the life cycle hook will also be deleted automatically.
Comparison of Options API and Composition API life cycle
beforeCreate
-> usesetup()
created
-> usesetup()
beforeMount
->onBeforeMount
mounted
->onMounted
beforeUpdate
->onBeforeUpdate
updated
->onUpdated
beforeUnmount
->onBeforeUnmount
unmounted
->onUnmounted
errorCaptured
->onErrorCaptured
renderTracked
->onRenderTracked
renderTriggered
->onRenderTriggered
activated
->onActivated
deactivated
->onDeactivated
Options API Hook inside setup
beforeCreate
Not needed* created
Not needed* beforeMount
onBeforeMount
mounted
onMounted
beforeUpdate
onBeforeUpdate
updated
onUpdated
beforeUnmount
onBeforeUnmount
unmounted
onUnmounted
errorCaptured
onErrorCaptured
renderTracked
onRenderTracked
renderTriggered
onRenderTriggered
activated
onActivated
deactivated
onDeactivated
It can be seen from the above comparison:
beforeCreate
andcreated
are replacedsetup
- The hook naming has been increased by
on
- Added hook functions
onRenderTriggered
andonRenderTricked
beforeDestroy
name of 060aa35bfd7221 inbeforeUnmount
; thedestroyed
table isunmounted
provide and inject
Provide and inject start dependency injection, both of which can only be called using the current component instance during setup
Types of
interface InjectionKey<T> extends Symbol {}
function provide<T>(key: InjectionKey<T> | string, value: T): void
// without default value
function inject<T>(key: InjectionKey<T> | string): T | undefined
// with default value
function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
// with factory
function inject<T>(
key: InjectionKey<T> | string,
defaultValue: () => T,
treatDefaultAsFactory: true
): T
reactive、ref、toRefs
In vue2.x, the definition of data is in thedata
function, but in vue3.x, you can usereactvie
andref
to define the data
reactive
Return a responsive copy of the object.
const obj = reactive({ count: 0 })
Features: Responsive conversion is "deep". It will affect all nested attributes. Based on Proxy
, the returned proxy
object is not equal to the original object. It is recommended to use it only with the responsive proxy
object to avoid relying on the original object.
Types of
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
The function reactive
accepts an object as a parameter and returns a responsive object. Here, a generic constraint method is used to make the parameter types of the reactive
example:
<template>
<div>
<p>{{user.name}}</p>
<p>{{user.hobby}}</p>
<p v-for="item in user.sexs" :key="item.id">{{item.label}}</p>
</div>
</template>
<script>
import { defineComponent, reactive } from 'vue'
export default defineComponent({
setup() {
const user = reactive({
name: 'DarkCode',
hobby: '篮球',
sexs: [
{
id: 1,
label: '男'
},
{
id: 2,
label: '女'
}
]
})
return {
user
}
}
})
</script>
combined with toRefs using deconstruction
As you can see in the above example, we use user.name
, user.hobby
etc. on the page to be more cumbersome. So can you user
object and get its related attributes directly? This is not possible, because it will eliminate its responsiveness. But we can use toRefs
. toRefs is used to convert a reactive object into a common object .
<template>
<div>
<p>{{name}}</p>
<p>{{hobby}}</p>
<p v-for="item in sexs" :key="item.id">{{item.label}}</p>
</div>
</template>
<script>
import { defineComponent, reactive,toRefs } from 'vue'
export default defineComponent({
setup() {
const user = reactive({
name: 'DarkCode',
hobby: '篮球',
sexs: [
{
id: 1,
label: '男'
},
{
id: 2,
label: '女'
}
]
})
return {
...toRefs(user)
}
}
})
</script>
Note: reactive
will "unlock" all deep refs
, while keeping ref
as a responsive
<script>
import { defineComponent, reactive, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(1)
const obj = reactive({ count })
// ref will be unwrapped
console.log(obj.count === count.value) // true
// it will update `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// it will also update `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
}
})
</script>
When assigning ref
to the response attribute, the ref
will be automatically unpacked
<script>
import { defineComponent, reactive, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(1)
const obj = reactive({})
// assigning a ref to a reactive property
obj.count = count
console.log(obj.count) // 1
// ref will be automatically unwrapped.
console.log(obj.count === count.value) // true
}
})
</script>
reactive essence
- It is a
proxy
, and the return value is a response object ofproxy
- The parameter of the function is the object type. For the basic data type,
reactive
- Ability to monitor responsive object properties in depth
<script>
import { defineComponent, reactive } from 'vue'
export default defineComponent({
setup() {
const obj = reactive({
name: 'DarkCode',
age: 22
})
console.log(obj)
}
})
</script>
ref
Accepts an internal value and returns a responsive and variable ref
object. ref
object has a single attribute (.value) pointing to an internal value
Such as:
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
console.log(count.value)
count.value++
console.log(count.value)
}
})
</script>
或
<template>
<div>
{{count}}
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
console.log(count.value)
setInterval(() => {
count.value++
console.log(count.value)
},1000)
return {
count
}
}
})
</script>
If an object is assigned ref
value, in response to the object will approach reactive
imparting depth responsive
Types of
interface Ref<T> {
value: T
}
function ref<T>(value: T): Ref<T>
A Ref
generic interface is defined, a value variable is defined in the interface, and the type is determined by generics. The return value of ref
is of type Ref
Such as:
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref({
name: 'Darkcode',
age: 22
})
console.log(count.value.age)
count.value.age++
console.log(count.value.age)
return {
count
}
}
})
</script>
ref summary
- Method
ref
accepts one parameter, the type can be any type - The return value of the method is an interface (object) type
- To access or modify the value, it needs to be implemented in the form of .value
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref({
name: 'Darkcode',
age: 22
})
console.log(count)
}
})
</script>
toRefs
Able to convert a responsive object into a normal object, where each attribute of the result object points to the corresponding attribute of the original object ref
Such as:
<script>
import { defineComponent, reactive, toRefs } from 'vue'
export default defineComponent({
setup() {
const state = reactive({
foo: 1,
bar: 2
})
/*
Type of stateAsRefs:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
const stateAsRefs = toRefs(state)
// The ref and the original property is "linked"
state.foo++
console.log(stateAsRefs.foo.value)// 2
stateAsRefs.foo.value++
console.log(state.foo)// 3
}
})
</script>
When returning a responsive object from a composite function, toRefs
is very useful, so that when using components, the returned object can be deconstructed/expanded without losing the "responsive" .
<script>
import { defineComponent, reactive, toRefs } from 'vue'
function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2
})
return toRefs(state)
}
export default defineComponent({
setup() {
// can destructure without losing reactivity
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
})
</script>
toRefs
ref
references for attributes contained in the source object. ref
reference for a specific attribute, use toRef
toRefs summary
- Can convert a responsive object into a normal object
- The attribute of the obtained object has an implicit value attribute
- Each attribute of the obtained object can be regarded as one by one
ref
toRefs
is useful when deconstructing objects
readonly
can send an object (responsive or ordinary object) or a ref
, and return the original read-only proxy
proxy. The read-only proxy
proxy is "very deep": any nested attributes accessed will also be read-only .
Such as:
<script>
import { defineComponent, reactive, readonly, watchEffect } from 'vue'
export default defineComponent({
setup() {
const original = reactive({
count: 0
})
const copy = readonly(original)
console.log(copy)
watchEffect(() => {
// works for reactivity tracking
console.log(copy.count) // 0、1
})
// mutating original will trigger watchers relying on the copy
original.count++
// mutating the copy will fail and result in a warning
copy.count++ //warning
}
})
</script>
As with the reactive type, if any attribute uses ref
, the attribute will be automatically unpacked when the attribute is accessed through the proxy
<script>
import { defineComponent, ref, readonly } from 'vue'
export default defineComponent({
setup() {
const raw = {
count: ref(123)
}
const copy = readonly(raw)
console.log(raw.count.value) // 123
console.log(copy.count) // 123
}
})
</script>
isProxy
Check whether the object is proxy
proxy reactive
response or readonly
read-only mode.
isReactive
Check whether the object is a proxy
proxy object reactive
Such as:
<script>
import { defineComponent, reactive, isReactive } from 'vue'
export default defineComponent({
setup() {
const user = reactive({
name: 'DarkCode'
})
console.log(isReactive(user)) // true
}
})
</script>
If you create a proxy
readonly
, it will also return true
. But wrap another proxy
proxy object reactive
import { reactive, isReactive, readonly } from 'vue'
export default {
setup() {
const state = reactive({
name: 'John'
})
// readonly proxy created from plain object
const plain = readonly({
name: 'Mary'
})
console.log(isReactive(plain)) // -> false
// readonly proxy created from reactive proxy
const stateCopy = readonly(state)
console.log(isReactive(stateCopy)) // -> true
}
}
isReadonly
Whether the object is detected by the readonly
read only created proxy
agent.
toRaw
Return the original object represented by reactive
or readonly
It is just an escape port that can be used for temporary reading without proxy access/tracking overhead, and it can also be used for writing without triggering changes. It is not recommended to keep a persistent reference to the original object, and be cautious when using it.
Such as:
<script>
import { defineComponent, reactive, toRaw } from 'vue'
export default defineComponent({
setup() {
const foo = {
name: 'DarkCode'
}
const user = reactive(foo)
console.log(toRaw(user) === foo) // true
}
})
</script>
markRaw
Mark an object so that it will never be converted to a proxy, but return the object itself.
<script>
import { defineComponent, reactive, markRaw, isReactive } from 'vue'
export default defineComponent({
setup() {
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// also works when nested inside other reactive objects
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
}
})
</script>
be careful:
markRaw
and the following shallowXXX API allow us to selectively choose the default deep responsive/read-only conversion and embed original, non-proxy objects in the state diagram for the following reasons:
- Some values should not be responsive, such as responsible third-party class instances or Vue component instance objects.
- When rendering large lists with immutable data sources, skip proxy conversion can improve performance.
shallowReactive
Create a responsive agent that tracks the responsiveness of its own attributes, but does not perform deep responsive transformations of nested objects. Similar to our shallow copy.
Such as:
<script>
import { defineComponent, shallowReactive, isReactive } from 'vue'
export default defineComponent({
setup() {
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// mutating state's own properties is reactive
state.foo++
// ...but does not convert nested objects
isReactive(state.nested) // false
state.nested.bar++ // non-reactive
}
})
</script>
shallowReadonly
Similar to the above shallowReactive
, not much to say.
toRef
ref
for the attribute on the source responsive object, and then you can pass ref
to keep the responsive link with its source attribute.
Such as:
<script>
import { defineComponent, reactive } from 'vue'
export default defineComponent({
setup() {
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.foo++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.foo) // 3
}
})
</script>
toRef
is useful when passing the attribute ref
to the combination function.
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}
customRef
Create a custom ref
and explicitly control its dependency tracking and trigger an update. It needs a factory function, which receives track
and trigger
functions as parameters and returns objects get
and set
Such as:
<template>
<div>
<input type="text" v-model="text" />
</div>
</template>
<script>
import { defineComponent, customRef } from 'vue'
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default defineComponent({
setup() {
return {
text: useDebouncedRef('hello')
}
}
})
</script>
Types of
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>
type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T
set: (value: T) => void
}
computed and watch
computed
Use getter
function, and is getter
returns a responsive immutable value returned ref
object.
Such as:
<script>
import { defineComponent, computed, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
const plusOne = computed(() => count.value + 1) // 2
console.log(plusOne.value)
plusOne.value++ //error
},
})
</script>
In addition, it can also use get
and set
functions to create writable ref
objects.
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
Types of
// read-only
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>
// writable
function computed<T>(options: { get: () => T; set: (value: T) => void }): Ref<T>
watchEffect
Run a function immediately when tracking its dependencies responsively, and re-run the function when the dependencies change.
Such as:
<script>
import { defineComponent, watchEffect, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
watchEffect(() => console.log(count.value)) // 0、1
setTimeout(() => {
count.value++
}, 100)
},
})
</script>
Types of
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // default: 'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
watch
The watch function is used to listen to a specific data source and execute side effects in the callback function. The default is lazy, which means that the callback is executed only when the source data that is being listened to changes.
watch(source, callback, [options])
Parameter Description:
- source: can support string, Object, Function, Array; used to specify the responsive variable to be listened to
- callback: callback function executed
- options: supports deep, immediate and flush options.
Next, I will separately introduce how these three parameters are used. If you don't understand the use of watch, please read on:
Monitor data defined by reactive
Such as:
<script>
import { defineComponent, reactive, watch } from 'vue'
export default defineComponent({
setup() {
const state = reactive({
nickname: 'DarkCode',
age: 22
})
setTimeout(() => {
state.age++
}, 1000)
// 修改age的值时会触发watch的回调
watch(
() => state.age,
(curAge, preAge) => {
console.log('new value:', curAge, 'old value:', preAge)
}
)
},
})
</script>
Monitor the data defined by ref
<script>
import { defineComponent, ref, watch } from 'vue'
export default defineComponent({
setup() {
const count = ref(2021)
setTimeout(() => {
count.value++
}, 1000)
watch(count, (curCount, preCount) => {
console.log('new Value and old Value are:', curCount, preCount) // 2022,2021
})
},
})
</script>
Monitor multiple data
grammar:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
For example, to monitor the data defined by reactive and ref above:
<script>
import { defineComponent, reactive, ref, watch } from 'vue'
export default defineComponent({
setup() {
const count = ref(2021)
const state = reactive({
nickname: 'DarkCode',
age: 22
})
setTimeout(() => {
count.value++
state.age++
}, 1000)
watch([() => state.age, count], ([curAge, curCount], [preAge, preCount]) => {
console.log("新值:", curAge, "老值:", preAge); console.log("新值:", curCount,"老值:", preCount)
})
},
})
</script>
Listen to complex nested objects
Such as:
<script>
import { defineComponent, reactive, watch } from 'vue'
export default defineComponent({
setup() {
const state = reactive({
house: {
id: 11,
attrs: {
area: 111.2,
height: 12,
label: '学区房',
owner: 'DarkCode'
}
}
})
setTimeout(() => {
state.house.id++
}, 1000)
watch(
() => state.house,
(newT,oldT) => {
console.log('new value and oldT are:', newT, oldT)
},
{ deep: true }
)
},
})
</script>
If the third parameter deep:true
is not used, the data change cannot be monitored. We mentioned earlier that default 160aa35bfd80a5, watch is lazy , then under what circumstances is it not lazy, can the callback function be executed immediately? In fact, it is very simple to use, just set immediate: true
third parameter.
stop stop listening
watch
monitor we created in the component will automatically stop when the component is destroyed. If we want to stop a certain monitor before the component is destroyed, we can call watch()
function, the operation is as follows:
<script>
import { defineComponent, reactive, watch } from 'vue'
export default defineComponent({
setup() {
const state = reactive({
house: {
id: 11,
attrs: {
area: 111.2,
height: 12,
label: '学区房',
owner: 'DarkCode'
}
}
})
setTimeout(() => {
state.house.id++
}, 1000)
setTimeout(() => {
stopWatchHouse()
}, 3000)
const stopWatchHouse = watch(
() => state.house,
(newT,oldT) => {
console.log('new value and oldT are:', newT, oldT)
},
{ deep: true }
)
},
})
</script>
Compare watchEffect
:
- watchEffect does not need to manually pass in dependencies
- watchEffect will be executed once to automatically collect dependencies
- watchEffect cannot get the value before the change, only the value after the change
Vue3-Advanced
Custom hooks
If there are friends who are familiar with React, they are more familiar with hooks. In Vue3.x, custom hooks are provided for code reuse. mixins
that it has better performance and readability.
Such as: constructing a common hook in the usual development to process the data package request.
We will build two combinable hooks.
- The first hook will be used to directly interact with the rest of the API
- The second hook will depend on the first
/hooks/api.ts
import { ref } from 'vue'
export default function useApi(url: RequestInfo, options ?: RequestInit | undefined) {
const response = ref()
const request = async () => {
const res = await fetch(url, options)
const data = await res.json()
response.value = data
}
return {
response,
request
}
}
/hooks/products.ts
import useApi from './api'
import { ref } from 'vue'
export default async function useProducts() {
const { response: products, request } = useApi(
"https://ecomm-products.modus.workers.dev/"
)
const loaded = ref(false)
if(loaded.value === false) {
await request()
loaded.value = true
}
return {
products
}
}
/test.vue
<template>
<div>
<h3>Customers</h3>
<table id="customers" >
<tr>
<th>ID</th>
<th>title</th>
<th>category</th>
</tr>
<tr v-for="product in products" :key="product.id">
<td>{{product.id}}</td>
<td>{{product.title}}</td>
<td>{{product.category}}</td>
</tr>
</table>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import useProducts from "../hooks/products";
export default defineComponent({
async setup() {
const { products } = await useProducts()
return { products };
},
});
</script>
Note that setup
added to async
. Need to set the parent component <Suspense>
wrap the child component, such as parent.vue
:
<template>
<div>
<Suspense>
<template #default>
<HelloWorld></HelloWorld>
</template>
<template #fallback>
<h1>Loading...</h1>
</template>
</Suspense>
</div>
</template>
Let's look at an example of obtaining user information:
/hooks/user.ts
import useApi from "./api";
import { ref } from "vue";
export interface Location {
lat: number;
lng: number;
}
export interface Address {
street: string;
suite: string;
city: string;
zipcode: number;
geo: Location;
}
export interface User {
id: string;
name: string;
username: string;
email: string;
address: Address;
}
export default async function useUserss() {
const { response: users, request } = useApi<User[]>(
"https://jsonplaceholder.typicode.com/users"
);
const loaded = ref(false);
if (loaded.value === false) {
await request();
loaded.value = true;
}
return { users };
}
/component/User.vue
<script lang="ts">
import { defineComponent } from "vue";
import useUsers from "../hooks/users";
export default defineComponent({
name: "Users",
async setup() {
const { users } = await useUsers();
return { users };
},
});
</script>
Teleport
Why need
<teleport /> allows an element to be moved from one place to another.
With this understanding, we'll look at why you need to use Teleport characteristics of it, look at a small example: In sub-assembly Header
use into Dialog
components, the actual development we often use to under similar circumstances Dialog
, this time Dialog
is rendered into a layer of sub-components, and it becomes difficult to z-index
Dialog
should be an independent component. The DOM mounted by the top-level component of Vue should be completely stripped from the dom structure; at the same time, the value data
or props
Simply put, hopes to continue using Dialog
inside the component, and hopes that the rendered DOM structure is not nested in the component's DOM . At this time, Teleport is needed to play. We can wrap Dialog
<Teleport>
. At this time, a portal is established, which can transmit the content rendered by Dialog
Next, let’s take a small example to see how Teleport is used.
use
We hope that the dom rendered by Dialog and the top-level component are sibling nodes. Define an element for mounting index.html
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<div id="dialog"></div>
</body>
Dialog.vue
<template>
<teleport to="#dialog">
<div class="dialog">
<div class="dialog_wrapper">
<div class="dialog_header" v-if="title">
<slot name="header">
<span>{{ title }}</span>
</slot>
</div>
</div>
<div class="dialog_content">
<slot></slot>
</div>
<div class="dialog_footer">
<slot name="footer"></slot>
</div>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
return {
title: '登录'
}
},
})
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。