Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use vue3 to imitate the side message prompt effect of Apple system

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces how to use vue3 to imitate the side message prompt effect of Apple system, the article is very detailed, has a certain reference value, interested friends must read it!

Dynamic effect preview

Recently, I am working on a graduation project. I want to add a side message prompt box imitating Apple system to Bishu system. Let's see the effect first.

Other UI libraries

Students who are familiar with front-end development may find that in Element UI this component is called Notification notification; in Bootstrap it is called Toasts.

Start

When I saw this component, I thought it was very cool. Today, I will show you how I achieve it step by step. If there is something wrong or can be optimized, please comment on it. ? (this component is implemented based on Vue3)

Component directory structure

Toasts

| |

|-- index.js / / registers the component to define global variables for calling

| |

| |-- instance.js / / Logic before and after manual instance creation |

| |

|-- toasts.vue / / message prompt HTMl

| |

|-- toastsBus.js / / A solution to remove $on and $emit from vue3

The approximate DOM structure of toasts.vue

... Index.js Registration component & define global variables

Here we register the component and define the global variable to call the

Import toast from'. / instance'import Toast from'. / toasts.vue'export default (app) = > {/ / register the component app.component (Toast.name, Toast); / / register the global variable, and then simply call $Toast ({}) to app.config.globalProperties.$Toast = toast;} instance.js to manually mount the instance

? Is this the focus of the full text?

First, we learn how to manually mount components to the page.

Import {createApp} from 'vue';import Toasts from'. / toasts'const toasts = (options) = > {/ / create parent container let root = document.createElement ('div'); document.body.appendChild (root) / / create Toasts instance let ToastsConstructor = createApp (Toasts, options) / / Mount parent element let instance = ToastsConstructor.mount (root) / / throw the instance itself to vue return instance} export default toasts

Give each created toasts the correct location

As shown in the figure, each toasts created will be arranged below the previous toasts (the gap here is 16px). To achieve this effect we need to know the height of the existing toasts.

/ / instance.js// here we need to define an array to store the current surviving toastslet instances = [] const toasts = (options) = > {... / / add the instance to the array instances.push (instance) / / replication height let verticalOffset = 0 / / traversing to get the current surviving toasts height and its gap accumulation instances.forEach (item = > { VerticalOffset + = item.$el.offsetHeight + 16}) / / accumulate the gap verticalOffset + = 16 / / assign the cheap length instance.toastPosition.y = verticalOffset.} export default toasts in the y-axis direction of the current instance.

Add active-timing shutdown function

Let's first analyze the business here:

Timed shutdown: gives an automatic shutdown time when the toast is created, and automatically shuts down when the timer ends.

Active shutdown: click the close button to close toast.

On this basis, we can add some humanized operations, such as stopping the automatic shutdown of a toast when the mouse is moved into it (other toast is not affected), and re-enabling it when the mouse is moved away.

... Import Bus from'. / toastsBus'import {ref, computed, onMounted, onBeforeUnmount} from 'vue'export default {props: {/ / automatic shutdown time (in milliseconds) autoClose: {type: Number, default: 4500}}, setup (props) {/ / whether const visible = ref (false) is displayed / / toast container instance const container = ref (null); / / toast itself height const height = ref (0) / / toast location const toastPosition = ref ({x: 16, y: 16}) const toastStyle = computed (() = > {return {top: `${toastPosition.value.y} px`, right:` ${toastPosition.value.x} px` }}) / / id const id of toast = ref ('') / / function afterLeave () {/ / tells instance.js that a shutdown operation () Bus.$emit ('closed',id.value) is needed after the animation ends } / / after toast enters the animation, function afterEnter () {height.value = container.value.offsetHeight} / / timer const timer = ref (null) / / Mouse enters toast function clearTimer () {if (timer.value) clearTimeout (timer.value)} / / Mouse moves out of toast function createTimer () {if (props.autoClose) {timer.value = setTimeout (() = > {visible.value = false}) Props.autoClose)}} / / destroy function destruction () {visible.value = false} onMounted (() = > {createTimer () }) onBeforeUnmount (() = > {if (timer.value) clearTimeout (timer.value)}) return {visible, container, height, toastPosition, toastStyle, id, afterLeave, afterEnter Timer, clearTimer, createTimer, destruction}

Let's analyze the logic of toast shutdown in instance.js

Remove this toast from the survival array, and the traversal array shifts the toast position upward from this bar.

Remove the Dom element from the.

Call unmount () to destroy the instance.

/ / instance.jsimport {createApp} from 'vue' Import Toasts from'. / toasts'import Bus from'. / toastsBus'let instances = [] let seed = 1const toasts = (options) = > {/ / manually mount the instance let ToastsConstructor = createApp (Toasts Options) let instance = ToastsConstructor.mount (root) / / add a unique identifier to the instance instance.id = id / / display instance instance.visible = true. / / listen to the toasts.vue to close the event Bus.$on ('closed', (id) = > {/ / because all the' closed' events are listened for here So to match id, make sure if (instance.id = = id) {/ / call delete logic removeInstance (instance) / / delete the dom element document.body.removeChild (root) / / destroy the instance ToastsConstructor.unmount () }}) instances.push (instance) return instance} export default toasts / / delete logic const removeInstance = (instance) = > {if (! instance) return let len = instances.length / / find the subscript const index = instances.findIndex (item = > {return item.id = instance.id}) that needs to be destroyed / / remove instances.splice (index, 1) / / if there is still a living Toasts in the current array, you need to traverse and move the following Toasts up Recalculate displacement if (len {app.component (Toast.name, Toast) App.config.globalProperties.$Toast = toast;}

ToastsBus.js

Import emitter from 'tiny-emitter/instance'export default {$on: (... args) = > emitter.on (... args), $once: (... args) = > emitter.once (... args), $off: (... args) = > emitter.off (... args), $emit: (. Args) = > emitter.emit (... args)}

Instance.js

Import {createApp} from 'vue';import Toasts from'. / toasts'import Bus from'. / toastsBus'let instances = [] let seed = 1const toasts = (options) = > {/ / create parent container const id = `toasts_$ {seed++} `let root = document.createElement ('div') Root.setAttribute ('data-id', id) document.body.appendChild (root) let ToastsConstructor = createApp (Toasts, options) let instance = ToastsConstructor.mount (root) instance.id = id instance.visible = true / / repetition height let verticalOffset = 0 instances.forEach (item = > {verticalOffset + = item.$el.offsetHeight + 16}) verticalOffset + = 16 instance.toastPosition.y = verticalOffset Bus.$on (' closed' (id) > {if (instance.id = = id) {removeInstance (instance) document.body.removeChild (root) ToastsConstructor.unmount () }}) instances.push (instance) return instance} export default toasts Const removeInstance = (instance) = > {if (! instance) return let len = instances.length const index = instances.findIndex (item = > {return item.id = instance.id}) instances.splice (index, 1) if (len {return {top: `${toastPosition.value.y} px` Right: `$ {toastPosition.value.x} px`,}}) / / countdown const countDown = computed (() = > {return'2 seconds ago'}) const id = ref ('') / / after leaving function afterLeave () {Bus.$emit ('closed',id.value) } / / after entering function afterEnter () {height.value = container.value.offsetHeight} / / timer const timer = ref (null) / / Mouse enters function clearTimer () {if (timer.value) clearTimeout (timer.value)} / / Mouse moves out of function createTimer () {if (props.autoClose) {timer.value = setTimeout (() = > {visible.value = false}) Props.autoClose)}} / / destroy function destruction () {visible.value = false} onMounted (() = > {createTimer () }) onBeforeUnmount (() = > {if (timer.value) clearTimeout (timer.value)}) return {visible, toastPosition, toastStyle, countDown, afterLeave, afterEnter, clearTimer, createTimer, timer Destruction, container, height, id}} / / external container. Toast-container {width: 330px Box-shadow: rgba (0,0,0,0.1) 0px 2px 12px 0px; background-color: rgba (# F7F7F7, .6); border: 1px solid # E5E5E5; padding: 14px 13px; z-index: 1001; position: fixed; top: 0; right: 0; border-radius: 10px; backdrop-filter: blur (15px); display: flex; align-items: stretch; transition: all .3s ease Will-change: top,left;} / /-icon-.toast-icon, .toast-close {flex-shrink: 0;} .toast-icon {width: 30px; height: 30px; border-radius: 100%; display: inline-flex; align-items: center; justify-content: center } / / correct. Toast-icon.success {background-color: rgba (# 2BB44A, .15); color: # 2BB44A;} / / exception. Toast-icon.warning {background-color: rgba (# ffcc00, .15); color: # F89E23; font-weight: 600; font-size: 18px;} / / error. Toast-icon.error {font-size: 18px; background-color: rgba (# EB2833, .1) Color: # EB2833;} / / Information. Toast-icon.info {background-color: rgba (# 3E71F3, .1); color: # 3E71F3;} / / Custom picture. Toast-custom-img {width: 40px; height: 40px; border-radius: 10px; overflow: hidden; flex-shrink: 0 } / /-content-.toast-content {padding: 0 8px 0 13px; flex: 1;} / /-head-.toast-head {display: flex; align-items: center; justify-content: space-between;} / / title.toast-title {font-size: 16px Line-height: 24px; color: # 191919; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;} / / time.toast-countdown {font-size: 12px; color: # 929292; line-height: 18.375px;} / /-body -. Toast-body {color: # 191919 Line-height: 21px; padding-top: 5px;} / /-close-.toast-close {padding: 3px; cursor: pointer; font-size: 18px; width: 24px; height: 24px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;}. Toast-close:hover {background-color: rgba (# E4E4E4, .5) } / /-operate-.toast-button-confirm {font-weight: 600; color: # 3E71F3;} .toast-button-confirm:hover {color: # 345ec9;} / / successful. Toast-button-confirm.success {color: # 2BB44A;} .toast-button-confirm.success:hover {color: # 218a3a;} / / exception. Toast-button-confirm.warning {color: # F89E23 } .toast-button-confirm.warning:hover {color: # df8f1f;} / / Information. Toast-button-confirm.info {color: # 3E71F3;} .toast-button-confirm.info:hover {color: # 345ec9;} / / error. Toast-button-confirm.error {color: # EB2833;} .toast-button-confirm.error:hover {color: # c9101a } / * Animation * / .toast-enter-from,.toast-leave-to {transform: translateX (120%);} .v-leave-from,.toast-enter-to {transform: translateX (00%);}

Main.js

Import {createApp} from 'vue'import App from'. / App.vue'const app = createApp (App) import'@ / assets/font/UIcons/font.css'// install toastsimport toasts from'. / components/toasts'app.use (toasts) .mount ('# app')

Use

It's shameful to send import {getCurrentInstance} from 'vue'export default {setup () {const instance = getCurrentInstance () function clickHandle () {/ / when calling the global variable of vue3 here. I wonder if you guys have any other good way to instance.appContext.config.globalProperties.$Toast ({type:' info', title: 'this is a title' Message: 'this article is to sort out the main logic of the mount function. Designed to sort out the basic processing flow (Vue version 3.1.1).' })} return {clickHandle}} above are all the contents of this article entitled "how to use vue3 to imitate the side message prompt effect of Apple system". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report