泽恩小站-教程区 Help

搜索文章

前面 Django 开发的部分已经实现了搜索接口,本章就基于此将其对应的搜索功能补充完整。

准备工作

为了让用户在博客的所有页面都能找到搜索框,将它放到页眉里是个不错的注意。

修改 BlogHeader.vue ,将搜索框的外观放进去:

<!-- frontend/src/components/BlogHeader.vue --> <template> <div id="header"> <div class="grid"> <div></div> <h1>My Drf-Vue Blog</h1> <div class="search"> <form> <input type="text" placeholder="输入搜索内容..."> <button></button> </form> </div> </div> <hr> </div> </template> <script> export default { name: 'BlogHeader' } </script> <style scoped> #header { text-align: center; margin-top: 20px; } .grid { display: grid; grid-template-columns: 1fr 4fr 1fr; } .search { padding-top: 22px; } /* css 来源:https://blog.csdn.net/qq_39198420/article/details/77973339*/ * { box-sizing: border-box; } form { position: relative; width: 200px; margin: 0 auto; } input, button { border: none; outline: none; } input { width: 100%; height: 35px; padding-left: 13px; padding-right: 46px; } button { height: 35px; width: 35px; cursor: pointer; position: absolute; } .search input { border: 2px solid gray; border-radius: 5px; background: transparent; top: 0; right: 0; } .search button { background: gray; border-radius: 0 5px 5px 0; width: 45px; top: 0; right: 0; } .search button:before { content: "搜索"; font-size: 13px; color: white; } </style>

代码大部分是在定义搜索框的外观,有兴趣的同学自行研究。

现在你的博客标题的右边应该就出现一个像模像样的搜索框了(无功能)。

接下来开始正式编写搜索的逻辑。

编程式导航

为了让搜索框发挥功能,继续修改 BlogHeader.vue

<!-- frontend/src/components/BlogHeader.vue --> <template> ... <div class="search"> <form> <input v-model="searchText" type="text" placeholder="输入搜索内容..."> <button v-on:click.prevent="searchArticles"></button> </form> </div> ... </template> <script> export default { name: 'BlogHeader', data: function () { return { searchText: '' } }, methods: { searchArticles() { const text = this.searchText.trim(); if (text.charAt(0) !== '') { this.$router.push({name: 'Home', query: { search: text }}) } } } } </script> ...
  • v-model 指令可以在表单控件上创建双向数据绑定 。具体来说,就是上面的 <input> 中的数据和 Vue 管理的 searchText 数据绑定在一起了,其中一个发生变化,另一个也会改变。

  • v-on:click 绑定了按钮的鼠标点击事件 ,即点击则触发 searchArticles() 方法。 .prevent 用于阻止按钮原本的表单提交功能。

前面章节我们用 <router-link> 标签实现了路由跳转。在必要时候路由跳转也可以通过脚本来动态实现 ,也就是上面代码的 this.$router.push(...) 了。注意 this.$routethis.$router ,前者代表路径对象,后者代表路由器对象。

总之,点击按钮触发 searchArticles() ,然后此方法将 searchText 作为参数跳转到新的路径。

正餐

页面跳转实现了,但是因为前面章节把 get_article_data() 方法中的 url 写死为 '/api/article' 了,所以跳转之后还不能够根据路径的中 search 参数展示筛选后的数据。因此要换个战场 ,在 ArticleList.vue 里进行修改(主要是 Javascript 部分)。

旧的翻页 <router-link> 仅考虑了路径参数中的 page 值。为了在翻页后取得包括 pagesearch 的正确路径,新写一个方法 get_path()

<!-- frontend/src/components/ArticleList.vue --> ... <script> ... export default { ... methods: { ... get_path: function (direction) { let url = ''; try { switch (direction) { case 'next': if (this.info.next !== undefined) { url += (new URL(this.info.next)).search } break; case 'previous': if (this.info.previous !== undefined) { url += (new URL(this.info.previous)).search } break; } } catch { return url } return url } }, ... } </script> ...

如果下一页的路径存在,那么则返回其带参数的路径,否则就返回无任何参数的首页路径。

有了 get_path() 获取到路径后,还需要将路径用到请求数据的接口里。

修改 get_article_data() 方法,如下面这样:

<!-- frontend/src/components/ArticleList.vue --> ... <script> ... export default { ... methods: { ... get_article_data: function () { let url = '/api/article'; let params = new URLSearchParams(); // 注意 appendIfExists 方法是原生没有的 // 原生只有 append 方法,但此方法不能判断值是否存在 params.appendIfExists('page', this.$route.query.page); params.appendIfExists('search', this.$route.query.search); const paramsString = params.toString(); if (paramsString.charAt(0) !== '') { url += '/?' + paramsString } axios .get(url) .then(response => (this.info = response.data)) } }, ... } </script> ...

这里的代码抛弃了之前用的字符串拼接的方式,改为专门用于处理路径参数的 URLSearchParams() 对象。为了将路径中已有的参数添加到 URLSearchParams() 中,可以用其本身的 append() 方法,但此方法不能判断值是否存在 ,从而获得类似 http://localhost:8080/?page=undefined 这种错误的路径。

解决方法可以在 methods 里写一个 appendIfExists() 方法,调用它来排除错误路径。还有一种方法是由于 JavaScript 是基于原型链的语言,因此可以通过原型链将此方法添加到已有对象中(包括内置原生对象),以扩展此对象的功能。

具体实施方法就是在 main.js 中写入:

// frontend/src/main.js import ... URLSearchParams.prototype.appendIfExists = function (key, value) { if (value !== null && value !== undefined) { this.append(key, value) } }; createApp(App)...;

因为 main.js 在 Vue 初始化时必然会执行,如此一来URLSearchParams 对象就有了这个 appendIfExists() 了。

把这些脚本写好后,就可以修改路由的模板了:

<!-- frontend/src/components/ArticleList.vue --> <template> ... <div id="paginator"> <span v-if="..."> <router-link :to="get_path('previous')"> Prev </router-link> </span> <span class="...e"> ... </span> <span v-if="..."> <router-link :to="get_path('next')"> Next </router-link> </span> </div> </template> ...

:tov-bind:to 的简写,意思是“将 to 属性和 get_path(...) 的返回值保持一致”。如果不需要这种响应式行为,也可以 to="/abc" 这样直接赋值给属性。

**这就搞定了。**随便搜索点东西看看效果:

P230 1

翻页试试,看看路径和文章数据的变化,应该都是正常工作的。

Last modified: 06 January 2025