Cet article vous apporte des connaissances pertinentes sur Vue3. Il présente principalement comment Vue3 implémente un champ de recherche global. Je partagerai mes idées d'implémentation complètes, j'espère que cela vous aidera si vous en avez besoin. aide.
Préface : Depuis que j'ai appris vue, je suis obsédé par la fonction globale commande + K du site officiel de vue pour afficher la recherche globale par mot-clé. Il se trouve qu'un projet récent doit également implémenter une fonction de recherche globale, et il se trouve que je peux apprendre l'idée de cette fonction en payant. Le niveau des didacticiels sur Internet est inégal, et il se trouve que j'ai utilisé une fonction similaire au fil d'Ariane contextuel global dans un projet précédent, j'ai donc tiré des déductions et écrit un champ de recherche global dont notre projet a besoin, et j'aimerais partager mes idées.
Remarque : Cet article ne vous apprendra pas comment écrire du code tout de suite, mais servira de guide pour vous guider étape par étape pour comprendre les idées de conception de ce composant. Cela sera expliqué du point de vue de "Si je suis un débutant, si quelqu'un peut me dire cela lorsque j'apprends cette connaissance, alors je peux la comprendre rapidement", Il vaut mieux apprendre un poisson à une personne que de apprends-lui un poisson. À pêcher . J'espère que vous pourrez élargir votre réflexion et tirer des conclusions en lisant cet article.
Fichier
Fichier
Fichier
2. Le style du champ de recherche
enveloppé dans un dans le. SearchBar.vue fichier. input pour procéder rapidement à l'apprentissage suivant. Mais nous devons d'abord clarifier notre réflexion. Ce composant apparaîtra en haut de notre page, il doit donc utiliser une disposition absolue à l'intérieur du composant. Allons dans SearchBar.vue
pour définir un style pour le div
le plus externe. Les autres styles ici sont écrits en utilisant Uno CSS
, ce qui est inutile. Les amis qui l'ont vécu n'ont pas à s'inquiéter, c'est juste un style simple et n'a rien à voir avec le contenu central de cet article. (Le CSS écrit sous forme de propriétés calculées n'a pas de signification particulière dans ce scénario, mais il s'agit simplement d'une plus grande considération lors de la conception) .png" alt="Explication graphique détaillée des étapes pour implémenter le champ de recherche globale dans Vue3 (avec code)" chargement="lazy"/>
hSearchBar.vue
去设置一个样式给最外层的 div
,这里其它样式的写法使用的是 Uno CSS
,没用过的小伙伴也不需要担心,它只是单纯的样式,和本文中心内容不牵扯。(CSS写成计算属性在这个场景也毫无特殊意义,只是单纯设计时考虑多了)
打开之前准备的 SearchBar.ts 文件,从 vue 里引入这两个函数,并且把在上一步写好的简陋版搜索框(SearchBar.vue)引入到这个文件内。
看过我之前文章 Vue3实现一个 Toast 的读者可能会比较熟悉一点点,但是在那一篇文章内由于我也是初次接触这两个函数,所以当时总结的也不是特别精确,所以重新捋清思路,这里再讲解一下。
首先我们从官网的介绍,先看一下这个函数的定义。
可以看出,这个函数第一个参数是必填的,可以是一个 string
和 Component
,这篇文章重点讨论参数为 Component
的情况。重点是这个函数的返回值,是一个 VNode
et la fonction render (point clé) Ouvrez le fichier SearchBar.ts préalablement préparé, importez ces deux fonctions depuis
string
et un Component
. Cet article se concentre sur la situation du paramètre Component
. . Le fait est que la valeur de retour de cette fonction est un VNode
, que vous devez connaître, 🎜Virtual Node🎜 Les lecteurs de cet article ne sont peut-être pas aussi clairs sur le principe du 🎜dom🎜 virtuel. , mais je pense que vous devez connaître son mécanisme de base. 🎜Vue🎜 restitue d'abord le 🎜dom virtuel --> puis le convertit en un vrai dom🎜. 🎜Ne vous précipitez pas pour écrire le code. Je pense que vous connaissez peut-être mieux cette façon d'écrire, comme la simple boîte contextuelle que nous avons écrite dans le fichier SearchBar.vue. Le style de l'ensemble du composant est écrit dans le composant fourni par Vue, mais il faut savoir que Vue termine toujours la construction du dom virtuel en appelant h() en bas. Et n'est qu'un sucre syntaxique fourni par Vue pour vous permettre de développer avec le natif familier html. (Eh bien, vous pouvez le comprendre de cette façon)
Ensuite, nous pouvons suivre l'introduction de la fonction h() ci-dessus. Le premier paramètre qu'elle reçoit peut être Component
, puis notre SearchBar.vue
不就是组件吗?那如果我不想使用 去展示这个组件的话,我是否可以这样写呢?h(SearchBar.vue)
。没错,是的,你就是可以这样写。别忘了 h
的返回值就是我们想拿到的 Vnode ,所以按照正确的写法是这样的。
让我们回到 SearchBar.ts
文件。
首先思考,这个搜索框一定有一个出现的函数,和一个消失的函数?,ok,起名字,一个 present,一个 dismiss 。
接下来我需要创建出一个 VNode ,然后想办法处理成真实 dom。经过上面的学习,第一步马上就可以想到下面的写法。
下面这位更是重量级,render()
函数。虚拟 dom 有了,真实dom 该如何拿到呢? Vue 为我们提供了这样一个函数,这里我们需要重点去看这个函数的类型是值,是一个 RootRenderFunction
类型的。
这里我们转变一下思路,我们看一下 render 函数的第二个参数是 一个 container:HostElement ,然后让我们打开我们 main.ts 文件,我们跳进 mount
的定义部分,发现神奇的地方了吗,我们虽然不知道 HostElement 的类型是什么,但是你知道你 mount
函数内填的参数是什么了吗?(忘掉的转头自觉复习官网哈。)
没错,就是全局唯一的一个真实 dom,一个朴实无华的id叫 app
pour afficher ce composant, puis-je l'écrire comme ceci ? h(SearchBar.vue)
. Oui, oui, vous pouvez l'écrire comme ça. N'oubliez pas que la valeur de retour de h
est le Vnode que nous voulons obtenir, donc la bonne façon de l'écrire est comme ceci.
SearchBar.ts
. 🎜Premier Pensez-y, ce champ de recherche doit avoir une fonction pour apparaître et une fonction pour disparaître ? Ok, donnons-lui un nom, un 🎜présent🎜 et un 🎜rejeter🎜. render()
. Maintenant que nous avons un 🎜dom🎜 virtuel, comment pouvons-nous obtenir un 🎜dom🎜 réel ? 🎜Vue🎜 nous fournit une telle fonction. Ici, nous devons nous concentrer sur le fait que le type de cette fonction est une valeur, qui est un type RootRenderFunction
. 🎜🎜🎜🎜ici Changeons notre façon de penser et voyons que le deuxième paramètre de la fonction 🎜render🎜 est un 🎜container:HostElement🎜, puis ouvrons notre fichier 🎜main.ts🎜 et passons à la définition de la partie mount
, Avez-vous découvert un lieu magique ? Je ne sais pas quel est le type de 🎜HostElement🎜, savez-vous quels paramètres sont renseignés dans votre fonction mount
? (Si j'avais oublié, je me suis retourné et j'ai consciemment consulté le site officiel.)app code>. 🎜En raison du manque d'espace, vous pouvez d'abord comprendre brièvement ici. La fonction 🎜render🎜 enveloppera votre 🎜dom🎜 virtuel dans un élément 🎜dom🎜 réel, mais vous devez lui donner un véritable 🎜shell dom🎜 pour indiquer où il est rendu. le 🎜dom🎜 virtuel à. 🎜<li><p>ok, après avoir obtenu un dom virtuel packagé, l'étape suivante consiste à indiquer au navigateur où afficher cet élément. Ce à quoi nous devons penser ici, c'est que puisqu'il peut être affiché globalement, il doit être affiché sur tous les composants. <img src="https://img.php.cn/upload/article/000/000/020/2684ad00bc24159a077a8a166c9d8d3b-16.png" alt="Explication graphique détaillée des étapes pour implémenter le champ de recherche globale dans Vue3 (avec code)" loading="lazy">Le plus simple est de le faire apparaître dans le premier élément de <strong>body</strong>, il sera alors au même niveau que tous les composants de notre page web (astuce : généralement tous les composants de notre page seront écrits dans l'un des <strong> body</strong> <strong>div</strong> Quoi ? Vous me demandez pourquoi ? S'il vous plaît ouvrez votre <strong>index.html</strong> et voyez si vous avez oublié que notre <strong>App.vue</strong> est accrochée dans cet élément réel avec <strong>id app</strong> )<img src="https://img.php.cn/upload/article/000/000/020/659e9d144b30400682dc69d8bf2b853c-17.png" alt="Explication graphique détaillée des étapes pour implémenter le champ de recherche globale dans Vue3 (avec code)" loading="lazy">En fait, l'idée de notre fonctionnement est très simple. Lorsque j'appuie sur le bouton de recherche globale, vous insérez mon élément avant que les composants <code><div id="app"> ne suffisent. <img src="https://img.php.cn/upload/article/000/000/020/659e9d144b30400682dc69d8bf2b853c-18.png" alt="Explication graphique détaillée des étapes pour implémenter le champ de recherche globale dans Vue3 (avec code)" chargement="lazy"><code><div id="app"> 的元素之前插入我的组件即可。<img src="https://img.php.cn/upload/article/000/000/020/659e9d144b30400682dc69d8bf2b853c-18.png" alt="Explication graphique détaillée des étapes pour implémenter le champ de recherche globale dans Vue3 (avec code)" loading="lazy"><li><p>ok,到这里我们已经可以看到基本效果了,我们来测试一下。让我们在 <code>App.vue
组件内随便写一个按钮,然后调用 SearchBarCreator
实例身上的 present
方法。(maker 感觉不是那么合理,之后我们将 SearchBarMaker
变更为 SeachBarCreator
的叫法,仅仅是名字变了而已,逻辑什么的根本没变哦。?)效果如下:到这里 searchBar 已经可以呈现在页面上了,但是我们还不知道怎样让它消失,其实也非常简单,我们只需要在合适的时机移除这个 dom 元素即可。在这里我们需要知道一点,我们需要将 searchBar
提升到当前文件的全局,不能仅只在 open
中去 new
了。
ok,我们测试一下
写到这里的时候,你可能发现了一个小问题,当我一直去按搜索按钮的时候,它会出现多个搜索框,但是我们希望的是它在全局只能出现一个搜索框。换个角度思考,也就是同一时间,这个被我们 new
出来的 SeachBar
实例只能出现一个。思考一下?,我加一个变量,isShowing 是否正在被展示
,如果正在被展示的话,那么用户再次调用 present
的时候,我就去调用实例自身的 dismiss
方法让它消失,是否可行呢?
测试一下:
OK,看来完美解决当前的问题了。
在上面的这种情况下,我们已经可以在 App.vue
文件内去 new
一个实例来调用这个搜索框了。但是我们加入现在需要在 XXX.vue
文件内调用这个搜索框呢?我难道还需要重新去引入,然后重新 new
App.vue
, puis appelons la méthode present
sur l'instance SearchBarCreator
. (🎜maker🎜 Cela ne semble pas si raisonnable. Plus tard, nous avons changé le nom de SearchBarMaker
en SeachBarCreator
. Seul le nom a changé, et la logique n'a pas changé du tout. .? )L'effet est le suivant :🎜🎜🎜🎜Ici🎜searchBar🎜 peut être présentée sur la page, mais nous ne savons pas encore comment la faire disparaître. C'est en fait très simple, il suffit de supprimer cet élément 🎜dom🎜. le bon moment. Ici, nous devons savoir Un point, nous devons promouvoir searchBar
dans la portée globale du fichier actuel. Nous ne pouvons pas simplement accéder à new
dans open
. SeachBar
issue de notre new
peut apparaître. Pensez-y ?, j'ajoute une variable pour déterminer si isShowing est affiché
. S'il est affiché, alors lorsque l'utilisateur appellera à nouveau present
, j'appellerai l'instance. lui-même. Est-il possible d'utiliser la méthode dismiss
pour le faire disparaître ? new
dans le fichier App.vue
pour appeler ce champ de recherche. Mais que se passe-t-il si nous ajoutons que nous devons maintenant appeler ce champ de recherche dans le fichier XXX.vue
? Dois-je le réintroduire, puis à nouveau nouveau
? nonono, un certain patron a dit que les programmeurs sont très paresseux et ne peuvent pas écrire du code répétitif d'aussi bas niveau. Alors comment y parvenir🎜Ouvrez le fichier useSearch.ts que nous avons préparé auparavant, nous convertissons l'instance SearchBar précédemment générée globalement dans App.vue
et la transformons en un fichier App.vue
的全局生成的这个 SearchBar 实例转换思路,使它在全局的一个 ts 文件内生成一个,然后把这个实例自身的一些方法封装成函数,暴露给外部。那么我就可以在全局任意一个地方去调用这个实例身上的这两个方法。
让我们在 App.vue
去试一下。
这是我们之前的 App.vue
文件的调用方法。我们改造一下它。我们再次测试一下功能有没有什么问题
如此一来就方便很多了,我们可以在任意位置去调用这个“唯一的搜索框”
再此之前,我们需要理解一个概念,注意我们的 main.ts
文件,我们是把谁挂在了全局的那一个 id='app'
的真实 dom 下的?
没错,就是前面我们提到的 App.vue 组件。
那么假如我在这个 App.vue
组件挂载的时候,给全局 window 对象身上添加一个键盘事件,是不是就可以了呢?怎么添加呢?其实非常非常简单,要用到见组合按键,我们就需要使用到 “keydown”,具体为什么不是 “keypress” ,读者可以自行查阅这两者的区别,不属于本文的主要探讨内容。
这时候,我们先来按一下 command
看看打印的内容是什么。这里重点的内容是该键盘事件身上的metaKey
属性。在这里我们还可以推算出按下 “ctrl” 的事件为
keydown 事件支持多个按键同时按下。当我们同时按下 “command” 和 “K” 键,会发生什么呢?但是我们发现好像并没有 K:true
这个属性呀,那我们怎么去判断呢?别着急接着往下看。
我们可以看到键盘事件 event 身上有个 key 属性,它的值恰好是字符串类型的 “k”,
这里我直接公布写法,js 允许我们这样判断是否同时按下两个按键。
我们测试一下,我们去吧 App.vue 文件内的这两个按钮给去掉然后再打印一下我们按下 command
和 k
ts global. Générez-en un, puis encapsulez certaines des méthodes de cette instance elle-même en fonctions et les exposent à l'extérieur. Ensuite, je peux appeler ces deux méthodes sur cette instance n'importe où dans le monde.
App.vue
. App.vue
. Transformons-le. Testons à nouveau la fonction Y a-t-il un problème>C'est beaucoup plus pratique. Nous pouvons appeler cela « champ de recherche uniquement » à n'importe quel endroit
main.ts
, qui sommes-nous suspendus dans le fichier global id='app'
🎜dom🎜? App.vue
est monté, est-ce que ça va ? Comment l'ajouter ? En fait, c'est très, très simple. Pour utiliser la combinaison de touches, nous devons utiliser 🎜"keydown"🎜 Plus précisément, pourquoi ce n'est pas 🎜"keypress"🎜 Les lecteurs peuvent vérifier eux-mêmes la différence entre les deux. pas la discussion principale de cet article. 🎜🎜🎜🎜this une fois, cliquons d'abord sur commande
pour voir ce qui est imprimé. L'accent est mis ici sur l'attribut metaKey
sur l'événement clavier. Ici, nous pouvons encore le on en déduit que l'événement d'appui sur 🎜"ctrl"🎜 est 🎜🎜🎜🎜🎜keydown🎜 prend en charge l'appui sur plusieurs touches en même temps. Que se passe-t-il lorsque l'on appuie simultanément sur les touches « commande » et « K » ? Mais nous avons constaté que ne semble pas l'être. Il n'y a pas d'attribut K:true
, alors comment le juger ? Ne vous inquiétez pas et continuez à baisser les yeux. 🎜🎜🎜🎜Nous pouvons voir que l'événement clavier 🎜event🎜 a un attribut 🎜key🎜, et sa valeur se trouve être de type chaîne 🎜"k"🎜, 🎜command
et k
. 🎜Testez-le : 🎜🎜🎜🎜🎜 7. Ajoutez l'animation qui apparaît 🎜🎜🎜🎜 Comme nous pouvons le voir ci-dessus, l'apparition soudaine semble un peu abrupte. J'espère que ce champ de recherche pourra avoir un léger effet panoramique lorsqu'il apparaîtra (similaire à l'effet ci-dessous). Comment puis-je procéder ? ?🎜🎜Ici, j'introduis une idée plus simple. Nous prédéfinissons une animation Css dans le style du fichier App.vue
, et proposons un bon nom. Il s'appelle"searchInput"App.vue
文件的 style 内预设一个 Css 动画,并起好名字。叫做 "searchInput"
然后回到我们 searBar.vue
的组件去,给我们这个组件最外层的起一个好听的名字,我这里就叫做 searchBarWrapper
。
然后回到我们的 SearchBar.ts
文件内,也就是放我们 SeachBarCreator 构造函数的那个文件内。(tips:不是 useSearch.ts 哦)
我这里解释一下思路,在调用 render 函数后,这个组件其实已经渲染成为一个真实的 dom 元素,只不过我们还没给它指定渲染的位置。既然是真实的 dom ,那么我们就可以通过 document.getElementById这个方法(querySelector同理,一个意思)
拿到这个SearchBar.vue组件
,接下来我只需要在调用 document.body.insertBefore
方法前,给它添加上刚刚我们在 App.vue
里预设好的类名,searchInput
,就完美达成我们想要的效果了。
注意:style ,这个点仅仅是类名选择器,不要忘记了基础知识。
测试一下效果:
在弹出框的 input 框实现自动聚焦相比于之前讲的就非常简单了,我在这里一笔带过了。只需要在 nextTick 中调用 input 本身的 focus 方法即可。
之所以不喜欢使用真代码去写文章而大量使用截图的原因是:我自己在搜索到自己想要的文章后,也会喜欢直接看有没有最后的成品代码,然后直接复制就拿过去用了,而往往忽略了自己动手去实现一遍才是真正理解了的过程。
所以我写代码的时候,尽量不写特别复杂的逻辑,而写一些很简单的几行代码去实现某一个功能。是因为我希望你们真正带入自己的思考,和一步步体会这个实现过程,从而举一反三。
如果你认真看了该文章,你也许会明白现在很多组件库的底层实现原理其实就是这样的,比如全局弹出的dialog ,modal 框等等。我们要去理解组件库组件实现的思路,而不是一味的复制粘贴。
这个搜索框有很多可以更加优化的地方,你们可以带入自己的思考去想一想。比如
1.如何保存搜索历史?
2.如何实现实时的给出搜索联想
与君共勉才是我的初衷...
这里贴出核心代码 SearchBar.ts
SearchBar.ts
, qui est le fichier où se trouve notre constructeur SeachBarCreator. (conseils : ne pas useSearch.ts)
Laissez-moi vous expliquer l'idée ici. Après avoir appelé la fonction render, ce composant a en fait été rendu dans un véritable élément dom, mais nous n'avons pas encore spécifié la position de rendu pour celui-ci. . Puisqu'il s'agit d'un véritable dom, alors nous pouvons obtenir ce composant SearchBar.vue
via la méthode document.getElementById (la même que querySelector, la même signification) code>, il me suffit alors d'ajouter le nom de classe que nous venons de prédéfinir dans <code>App.vue
avant d'appeler la méthode document.body.insertBefore
. obtiendra parfaitement l'effet souhaité. 🎜🎜🎜🎜Attention :style, ce point n'est qu'un sélecteur de nom de classe, n'oubliez pas les bases. 🎜🎜🎜🎜Test Voici l'effet : 🎜 🎜SearchBar.ts
est publié ici. J'espère que les lecteurs pourront l'utiliser uniquement comme référence et j'espère ne pas le copier et le coller directement. 🎜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("不需要关闭") } } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!