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

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

image.png

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


前言:自从学习 vue 以来,就对 vue 官网全局的 command + K 调出全局关键词搜索这个功能心心念念。恰好最近项目也是需要实现一个全局搜索的功能,也正好可以正大光明的带薪学习这个功能的思路。网上的教程水平参差不齐,而恰好之前的项目中我有做过一个类似于全局弹出面包屑的功能,于是举一反三写出了一个我们项目需要的全局搜索框,特来分享一下自己的思路。084a0d2ef7704518adcb830e497dd6b8_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

注意:本文不会马上教你如何编写代码,而是作为一个引路人,一步一步引导你去理解这个组件的设计思路。会以 “假如我是一个初学者,如果我在学习这个知识的时候,别人能这样告诉我,那么我也可以很快的去理解” 的角度去讲解 ,授人以鱼不如授人以渔。希望你在阅读本文的时候可以拓展思路,举一反三。

一. 文件准备


前期你需要准备三个文件,来完成这个全局搜索框

  1. SearchBar.ts 文件
  2. SearchBar.vue 文件
  3. useSearch.ts 文件

image.png

二. 搜索框的样式


样式问题不是本文的重点,你可以花费五分钟在 SearchBar.vue 文件内速写一个非常简易的正方形 div 包裹着一个 input 标签即可快速进行下面的学习。

但是首先我们需要理清思路,这个组件是会出现在我们页面的最顶部的,所以它组件内部需要用到绝对布局。我们去 SearchBar.vue 去设置一个样式给最外层的 div,这里其它样式的写法使用的是 Uno CSS,没用过的小伙伴也不需要担心,它只是单纯的样式,和本文中心内容不牵扯。(CSS写成计算属性在这个场景也毫无特殊意义,只是单纯设计时考虑多了)

image.png

image.png

image.png

三. 渲染函数 hrender 函数(重点)


打开之前准备的 SearchBar.ts 文件,从 vue 里引入这两个函数,并且把在上一步写好的简陋版搜索框(SearchBar.vue)引入到这个文件内。

image.png

看过我之前文章 Vue3实现一个 Toast 的读者可能会比较熟悉一点点,但是在那一篇文章内由于我也是初次接触这两个函数,所以当时总结的也不是特别精确,所以重新捋清思路,这里再讲解一下。

首先我们从官网的介绍,先看一下这个函数的定义。

image.png

可以看出,这个函数第一个参数是必填的,可以是一个 stringComponent,这篇文章重点讨论参数为 Component 的情况。重点是这个函数的返回值,是一个 VNode,这个你一定不陌生,Virtual Node ,看本篇文章的读者可能对虚拟 dom 的原理可能不是那么清楚,但是我相信你们一定知道它的基本机制。Vue 其实是先渲染 虚拟 dom -->然后 转换成真实 dom

先别急着写代码,我想你可能更清楚这样的写法,比如我们前面在 SearchBar.vue 文件内写的简单的弹出框。

image.png

整个组件的样式都是在 Vue 提供的 <template> 组件内写的,但是你要知道,Vue 在底层还是通过调用 h() 来完成虚拟 dom 的构建。而 <template> 仅仅只是 Vue 为了让你用熟悉的原生 html 开发而为你提供的语法糖🍬而已。(嗯,你可以这样理解)

那么我们可以根据上面 h() 函数的介绍,它接收的第一参数可以是 Component ,那我们这个 SearchBar.vue 不就是组件吗?那如果我不想使用 <template> 去展示这个组件的话,我是否可以这样写呢?h(SearchBar.vue)。没错,是的,你就是可以这样写。别忘了 h 的返回值就是我们想拿到的 Vnode ,所以按照正确的写法是这样的。

image.png

四. 编写 SearchBarMaker 构造函数和 present 方法


让我们回到 SearchBar.ts 文件。

image.png

首先思考,这个搜索框一定有一个出现的函数,和一个消失的函数🤔,ok,起名字,一个 present,一个 dismiss

image.png

接下来我需要创建出一个 VNode ,然后想办法处理成真实 dom。经过上面的学习,第一步马上就可以想到下面的写法。

image.png

下面这位更是重量级,render() 函数。虚拟 dom 有了,真实dom 该如何拿到呢? Vue 为我们提供了这样一个函数,这里我们需要重点去看这个函数的类型是值,是一个 RootRenderFunction 类型的。

image.png

这里我们转变一下思路,我们看一下 render 函数的第二个参数是 一个 container:HostElement ,然后让我们打开我们 main.ts 文件,我们跳进 mount的定义部分,

image.png

image.png

发现神奇的地方了吗,我们虽然不知道 HostElement 的类型是什么,但是你知道你 mount 函数内填的参数是什么了吗?(忘掉的转头自觉复习官网哈。)

没错,就是全局唯一的一个真实 dom,一个朴实无华的id叫 appdiv 元素。

image.png

由于篇幅限制,在这里你可以先暂时简单的理解,render 函数会将你的虚拟 dom 包装成一个真实 dom 元素,但是你需要给它一个真实的 外壳dom 来告诉它将虚拟 dom 渲染到哪个位置。

ok,拿到一个包装后的虚拟 dom ,接下来就是告诉浏览器在哪里渲染这个元素。这里我们需要思考🤔,既然是全局都可以弹出的,并且需要在所有组件之上弹出。

image.png

那么最简单的方法就是让它出现在 body的第一个元素,那么它一定会和我们网页所有的组件同级别(tips:通常我们所有的页面构成都会写在 body内 的一个 div 内。什么?你问我为什么?请打开你的 index.html 看一下,你是否忘记了我们的 App.vue 是挂在这个真实的,id为 app 的元素内的)

image.png

那其实我们的操作的思路就是非常简单的,当我按下全局搜索按钮,那么你就在 <div id="app"> 的元素之前插入我的组件即可。

image.png

ok,到这里我们已经可以看到基本效果了,我们来测试一下。让我们在 App.vue 组件内随便写一个按钮,然后调用 SearchBarCreator 实例身上的 present 方法。(maker 感觉不是那么合理,之后我们将 SearchBarMaker 变更为 SeachBarCreator 的叫法,仅仅是名字变了而已,逻辑什么的根本没变哦。

image.png

效果如下:

66a6f82060a2451da531beaa54506ff7_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

到这里 searchBar 已经可以呈现在页面上了,但是我们还不知道怎样让它消失,其实也非常简单,我们只需要在合适的时机移除这个 dom 元素即可。

image.png

在这里我们需要知道一点,我们需要将 searchBar 提升到当前文件的全局,不能仅只在 open 中去 new 了。

image.png

ok,我们测试一下

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

五. 优化 SearchBarCreator 构造函数的代码逻辑


写到这里的时候,你可能发现了一个小问题,当我一直去按搜索按钮的时候,它会出现多个搜索框,但是我们希望的是它在全局只能出现一个搜索框。换个角度思考,也就是同一时间,这个被我们 new 出来的 SeachBar 实例只能出现一个。思考一下🤔,我加一个变量,isShowing 是否正在被展示 ,如果正在被展示的话,那么用户再次调用 present 的时候,我就去调用实例自身的 dismiss 方法让它消失,是否可行呢?

image.png

测试一下:

065be5689d5341d8a6c4f96ecaac9287_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

OK,看来完美解决当前的问题了。

相关文章
|
9天前
vue3【实战】语义化首页布局
vue3【实战】语义化首页布局
28 2
|
9天前
|
存储 容器
vue3【实战】来回拖拽放置图片
vue3【实战】来回拖拽放置图片
19 2
|
9天前
|
JavaScript 开发工具 开发者
vue3【提效】使用 VueUse 高效开发(工具库 @vueuse/core + 新增的组件库 @vueuse/components)
vue3【提效】使用 VueUse 高效开发(工具库 @vueuse/core + 新增的组件库 @vueuse/components)
32 1
|
4天前
【vue3】Argumnt of type ‘history:RouterHistory;}is not assignable to paraeter of type ‘RouterOptions‘.
【vue3】Argumnt of type ‘history:RouterHistory;}is not assignable to paraeter of type ‘RouterOptions‘.
6 0
|
4天前
|
JavaScript
【vue3】vue3中路由hash与History的设置
【vue3】vue3中路由hash与History的设置
9 0
|
4天前
|
编解码 前端开发
【Vue3】解决电脑分辨率125%、150%及缩放导致页面变形的问题
【Vue3】解决电脑分辨率125%、150%及缩放导致页面变形的问题
11 0
|
4天前
|
JavaScript
【vue】 vue 翻页时钟制作,vue2、vue3
【vue】 vue 翻页时钟制作,vue2、vue3
11 0
|
2天前
|
JavaScript
|
4天前
|
JavaScript
【vue】el-dialog 内的tinymce弹窗被遮挡的解决办法 及 tinymce打开弹出菜单后直接关闭对话组件,导致该弹出菜单残留
【vue】el-dialog 内的tinymce弹窗被遮挡的解决办法 及 tinymce打开弹出菜单后直接关闭对话组件,导致该弹出菜单残留
17 6
|
1天前
|
存储 缓存 JavaScript
vue代码优化方案
【7月更文挑战第13天】 **Vue.js 优化要点:** 分解大组件以提高复用性和加载速度;利用计算属性与侦听器优化数据处理;使用Object.freeze()减少响应式数据;借助Vuex或Composition API管理状态;实现虚拟滚动和无限加载提升长列表性能;路由懒加载减少初始加载时间;用Vue DevTools检测性能瓶颈;定期代码审查与重构;应用缓存策略;遵循最佳实践与团队规范,提升应用整体质量。
10 2

相关实验场景

更多