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("不需要关闭")
    }
  }
}


相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
163 64
|
2月前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
142 60
|
26天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
99 3
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
57 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
52 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
58 1
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
20天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
110 1
|
1月前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
56 1
vue学习第一章