目录
四;封装 创建 body 元素的子标签结点的函数 useDOMCreate,将 teleport 标签中的内容放入到创建的这个结点,让HTML标签结构更加合理。
一;Teleport 内置组件
官方定义:
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。
使用场景:
我们在A组件中使用B组件时,B组件中的 DOM 结构会被渲染到 A 组件中书写 B 组件的对应位置,但是有时候我们不希望它显示在该位置,而是显示到Vue app之外的其他位置: 比如移动到body元素上,或者我们有其他的div#app之外的元素上;
个人理解:
1.标签内 to 属性 指定 写在 teleport 标签中的内容被放入到指定的标签结构当中。
2.to 属性接收一个字符串,内容是选中该某一 html 的 css 选择器属性 比如 .class 类属性 #id id属性,也可以是 html 标签元素,如 body。
3.teleport 标签中的内容会被放入该 css 选择属性所在的标签当中。为了使得 html 结构更加合理。
二;提示栏组件要实现的功能:
自定义提示栏提示状态(成功,失败,默认);自定义提示栏中的内容;自定义多久后消失;允许手动关闭提示栏;
注:想要实现自定义,其实就是父组件在使用该子组件的时候动态的向子组件传递对应 prop 内容,子组件通过 props 接收并使用,所以要预先设计好要接收哪些 props 的内容。
因为要自定义实现提示栏类型和提示内容,所以该 Message 组件接收俩个prop属性,一个是 type用于设置提示栏类型,一个是 message 用于展示提示栏的提示内容。
三;设计 Message 组件 实现基本的样式与功能
模板和样式使用的 bootstrap 不做讲解
<template>
<teleport to="#message">
<div class="alert message-info fixed-top w-50 mx-auto d-flex justify-content-between mt-2"
:class="classObject" v-if="isVisible">
<span>{{message}}</span>
<button type="button" class="close" aria-label="Close" @click.prevent="hide">
<span aria-hidden="true">×</span>
</button>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent, PropType, ref } from 'vue'
import useDOMCreate from '../hooks/useDOMCreate'
// 限制 提示栏的提示类型
export type MessageType = 'success' | 'error' | 'default'
export default defineComponent({
props: {
// 动态接收的提示信息
message: String,
// 动态接收的提示类型
type: {
type: String as PropType<MessageType>,
default: 'default'
}
},
emits: ['close-message'],
setup(props, context) {
// 创建插入结点的封装方法
useDOMCreate('message')
// 是否显示提示栏的标志
const isVisible = ref(true)
// 显示哪种类型的提示栏
const classObject = {
'alert-success': props.type === 'success',
'alert-danger': props.type === 'error',
'alert-primary': props.type === 'default'
}
// 点击取消后调用的函数
const hide = () => {
isVisible.value = false
context.emit('close-message', true)
}
return {
classObject,
isVisible,
hide
}
}
})
</script>
四;封装 创建 body 元素的子标签结点的函数 useDOMCreate,将 teleport 标签中的内容放入到创建的这个结点,让HTML标签结构更加合理。
这一步完成后,提示栏组件 Message 封装完成。
// 引入卸载生命周期--当组件被卸载的时候把创建的 DOM 元素也删掉
import { onUnmounted } from 'vue'
function useDOMCreate(nodeId: string) {
// 创建 div 标签
const node = document.createElement('div')
// 给 div 标签 绑定 id 属性
node.id = nodeId
// 给 body 元素添加子元素
document.body.appendChild(node)
// 当组件被卸载的时候把创建的 DOM 元素也删掉
onUnmounted(() => {
document.body.removeChild(node)
})
}
export default useDOMCreate
五:函数化调用该提示栏
createApp介绍:
返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。
接收俩个参数,第一个参数是组件对象(要实例化哪个组件对象),第二个参数是这个被实例化的组件需要的 prop 属性。
1.封装一个函数,在函数中使用 createApp 方法创建一个 Message 的组件实例,创建一个新的结点,把组件实例挂载到该结点上,设置定时器,显示超过时间后卸载掉该结点。
2.函数接收参数:Message组件需要的 prpo 属性,显示时间。
import { createApp } from 'vue'
import Message from './Message.vue'
// 限制提示栏的类型
export type MessageType = 'success' | 'error' | 'default'
// 定义函数,之后调用该函数就可以在需要显示提示栏的地方显示提示信息
const createMessage = (message: string, type: MessageType, timeout = 2000) => {
// 创建一个组件实例对象
// 第一个参数 自定义Message组件 第二个参数 该组件需要的 prop 属性
const messageInstance = createApp(Message, {
message,
type
})
// 创建结点
const mountNode = document.createElement('div')
// 把结点添加到 DOM树中
document.body.appendChild(mountNode)
// 调用组件实例对象的 mount 方法 把实例化的内容挂载到对应结点中
messageInstance.mount(mountNode)
// 定时器,到时间后卸载掉该结点
setTimeout(() => {
messageInstance.unmount(mountNode)
document.body.removeChild(mountNode)
}, timeout)
}
export default createMessage
六:使用提示栏组件以及合适会被触发
请求错误的提示信息
项目中使用 vuex 进行状态管理,vuex 中 仓库 state 中设置一个 error 字段,类型为对象,包含是否错误标志 status 和 错误提示信息 message
在 mutation 中配置 setError 回调函数,在axios的相应回调错误中进行触发 setError 改变 Vuex state 中 error 的状态。
在 App 组件中通过监听属性 watch 对 vuex error字段进行监视,若 error 对象 status 为 true 且 message 信息存在 则触发上方定义的 createMessage 函数进行 Message的挂载与展示
其他类型的提示信息:
在适当的位置调用该函数即可。