Vue3 如何实现一个全局搜索框(二)

简介: Vue3 如何实现一个全局搜索框

五. 编写全局唯一的调用实例


在上面的这种情况下,我们已经可以在 App.vue 文件内去 new 一个实例来调用这个搜索框了。但是我们加入现在需要在 XXX.vue 文件内调用这个搜索框呢?我难道还需要重新去引入,然后重新 new 吗?nonono,某位大佬说过,程序员都是很懒的,不可能写这种低级的重复代码的。那么该如何实现呢

打开我们之前准备的 useSearch.ts 文件,我们把之前在 App.vue 的全局生成的这个 SearchBar 实例转换思路,使它在全局的一个 ts 文件内生成一个,然后把这个实例自身的一些方法封装成函数,暴露给外部。那么我就可以在全局任意一个地方去调用这个实例身上的这两个方法。

image.png

让我们在 App.vue 去试一下。

这是我们之前的 App.vue 文件的调用方法。

image.png

我们改造一下它。

image.png

我们再次测试一下功能有没有什么问题

01afbc6ce609421dbec121eb1ffa7827_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

如此一来就方便很多了,我们可以在任意位置去调用这个“唯一的搜索框”

六. 添加全局的快捷键 Command + K


再此之前,我们需要理解一个概念,注意我们的 main.ts 文件,我们是把谁挂在了全局的那一个

id='app' 的真实 dom 下的?

image.png

没错,就是前面我们提到的 App.vue 组件。

那么假如我在这个 App.vue 组件挂载的时候,给全局 window 对象身上添加一个键盘事件,是不是就可以了呢?怎么添加呢?其实非常非常简单,要用到见组合按键,我们就需要使用到 “keydown”,具体为什么不是 “keypress” ,读者可以自行查阅这两者的区别,不属于本文的主要探讨内容。

image.png

这时候,我们先来按一下 command 看看打印的内容是什么。这里重点的内容是该键盘事件身上的metaKey 属性。

image.png

在这里我们还可以推算出按下 “ctrl” 的事件为

image.png

keydown 事件支持多个按键同时按下。当我们同时按下 “command” 和 “K” 键,会发生什么呢?

image.png

但是我们发现好像并没有 K:true 这个属性呀,那我们怎么去判断呢?别着急接着往下看。

我们可以看到键盘事件 event 身上有个 key 属性,它的值恰好是字符串类型的 “k”

image.png

这里我直接公布写法,js 允许我们这样判断是否同时按下两个按键。

image.png

我们测试一下,我们去吧 App.vue 文件内的这两个按钮给去掉

image.png

然后再打印一下我们按下 commandk 的时候。

image.png

afe0ebc9c5e14c329b6aa96d20319186_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

七. 添加出现的动画


在上面我们可以看到,这样突然的出现好像有一丝丝的突兀。我希望这个搜索框在出现的时候,可以有那么一丝丝的平移效果,(类似于下面的效果)该如何做呢?🤔

b57cccc75d3545f3b3dd551c1fda3676_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

我这里介绍一种较为简单的思路,我们在 App.vue 文件的 style 内预设一个 Css 动画,并起好名字。叫做"searchInput"

image.png

然后回到我们 searBar.vue 的组件去,给我们这个组件最外层的起一个好听的名字,我这里就叫做 searchBarWrapper

image.png

然后回到我们的 SearchBar.ts 文件内,也就是放我们 SeachBarCreator 构造函数的那个文件内。(tips:不是 useSearch.ts 哦) 我这里解释一下思路,在调用 render 函数后,这个组件其实已经渲染成为一个真实的 dom 元素,只不过我们还没给它指定渲染的位置。既然是真实的 dom ,那么我们就可以通过 document.getElementById这个方法(querySelector同理,一个意思)拿到这个SearchBar.vue组件 ,接下来我只需要在调用 document.body.insertBefore 方法前,给它添加上刚刚我们在 App.vue 里预设好的类名,searchInput ,就完美达成我们想要的效果了。

image.png

注意:style ,这个点仅仅是类名选择器,不要忘记了基础知识。

image.png

ea07aa7fad3b4d8693b441d6e8efd808_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

八. 自动聚焦


在弹出框的 input 框实现自动聚焦相比于之前讲的就非常简单了,我在这里一笔带过了。只需要在 nextTick 中调用 input 本身的 focus 方法即可。

image.png

总结:


之所以不喜欢使用真代码去写文章而大量使用截图的原因是:我自己在搜索到自己想要的文章后,也会喜欢直接看有没有最后的成品代码,然后直接复制就拿过去用了,而往往忽略了自己动手去实现一遍才是真正理解了的过程。

所以我写代码的时候,尽量不写特别复杂的逻辑,而写一些很简单的几行代码去实现某一个功能。是因为我希望你们真正带入自己的思考,和一步步体会这个实现过程,从而举一反三。

如果你认真看了该文章,你也许会明白现在很多组件库的底层实现原理其实就是这样的,比如全局弹出的dialogmodal 框等等。我们要去理解组件库组件实现的思路,而不是一味的复制粘贴。

这个搜索框有很多可以更加优化的地方,你们可以带入自己的思考去想一想。比如

1.如何保存搜索历史?

2.如何实现实时的给出搜索联想

与君共勉才是我的初衷...

源码


这里贴出核心代码 SearchBar.ts 文件的源码,希望读者可以仅作为参考使用,希望不要直接复制粘贴。

import { h, render } from "vue"
import SearchBar from "./SearchBar.vue"
class SearchBarCreator {
  container: HTMLElement
  appElement: HTMLElement | null
  showing: boolean
  _dismiss: () => void
  constructor() {
    this.container = document.createElement("div")
    this.showing = false
    this.appElement = document.body.querySelector("#app")
    this.present.bind(this)
    this.dismiss.bind(this)
    this._dismiss = this.dismiss.bind(this)
  }
  present() {
    if (this.showing) {
      this.dismiss()
    } else {
      const SearchBar = h(h(SearchBar))
      render(SearchBar, this.container)
      const searchBarWrapperDOM =
        this.container.querySelector("#searchBarWrapper")
      searchBarWrapperDOM?.classList.add("animate-searchInputAnimation")
      document.body.insertBefore(this.container, document.body.firstChild)
      this.showing = true
      this.appElement?.addEventListener("click", this._dismiss)
    }
  }
  dismiss() {
    if (this.showing && this.container) {
      render(null, this.container)
      document.body.removeChild(this.container)
      this.showing = false
      this.appElement?.removeEventListener("click", this._dismiss)
    } else {
      console.log("不需要关闭")
    }
  }
}


相关文章
|
6天前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
103 10
|
4月前
|
缓存 JavaScript PHP
斩获开发者口碑!SnowAdmin:基于 Vue3 的高颜值后台管理系统,3 步极速上手!
SnowAdmin 是一款基于 Vue3/TypeScript/Arco Design 的开源后台管理框架,以“清新优雅、开箱即用”为核心设计理念。提供角色权限精细化管理、多主题与暗黑模式切换、动态路由与页面缓存等功能,支持代码规范自动化校验及丰富组件库。通过模块化设计与前沿技术栈(Vite5/Pinia),显著提升开发效率,适合团队协作与长期维护。项目地址:[GitHub](https://github.com/WANG-Fan0912/SnowAdmin)。
733 5
|
1月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
245 1
|
1月前
|
缓存 JavaScript UED
除了循环引用,Vue3还有哪些常见的性能优化技巧?
除了循环引用,Vue3还有哪些常见的性能优化技巧?
144 0
|
2月前
|
JavaScript
vue3循环引用自已实现
当渲染大量数据列表时,使用虚拟列表只渲染可视区域的内容,显著减少 DOM 节点数量。
95 0
|
4月前
|
JavaScript API 容器
Vue 3 中的 nextTick 使用详解与实战案例
Vue 3 中的 nextTick 使用详解与实战案例 在 Vue 3 的日常开发中,我们经常需要在数据变化后等待 DOM 更新完成再执行某些操作。此时,nextTick 就成了一个不可或缺的工具。本文将介绍 nextTick 的基本用法,并通过三个实战案例,展示它在表单验证、弹窗动画、自动聚焦等场景中的实际应用。
409 17
|
4月前
|
JavaScript 前端开发 API
Vue 2 与 Vue 3 的区别:深度对比与迁移指南
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,在过去的几年里,Vue 2 一直是前端开发中的重要工具。而 Vue 3 作为其升级版本,带来了许多显著的改进和新特性。在本文中,我们将深入比较 Vue 2 和 Vue 3 的主要区别,帮助开发者更好地理解这两个版本之间的变化,并提供迁移建议。 1. Vue 3 的新特性概述 Vue 3 引入了许多新特性,使得开发体验更加流畅、灵活。以下是 Vue 3 的一些关键改进: 1.1 Composition API Composition API 是 Vue 3 的核心新特性之一。它改变了 Vue 组件的代码结构,使得逻辑组
1500 0
|
8天前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
103 2
|
3月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
529 0
|
3月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能