Day 24:路由搜查队-route.query

目前我们实现了即时搜寻显示书名相符的书单资料,但是当我切换到其他路由之後又想再回到上一页的搜寻结果,或是直接在当前路径重新整理页面时,搜寻栏位就被清空了,而书单资料因为搜寻栏位无字串值可供辨别,因此连带失去筛选条件,一切回到最一开始的样子。

事实上,网站中的栏位并不会记住使用者的输入值,甚至是存进 Vuex 的资料也会在刷新页面之後被清空,因此才需要每次在不同时机进入路由或元件时,都需要发送 API 重新取得资料再渲染到画面上,又或者是透过暂存在用户端的 LocalStorage 或 Cookie 以便日後取用。

以为没有地方可以存取关键字,但其实近在眼前就有个可以利用的工具,就是路由!大家可以观察最常使用的 Google 搜寻,假设我们在搜寻栏位输入「vue.js」,搜寻结果会导向「 https://www.google.com/search?q=vue.js 」(& 後面暂且略过),接着改搜寻「vuex」,变成导向「 https://www.google.com/search?q=vuex 」,有发现什麽相同和差别之处了吗?

$route.query物件

相同的是两者都在 /search 路由之後出现「?q=」,差别在於後方所接的是各自输入的搜寻关键字,而我们就是要利用「?」来记录搜寻字词,问号後方所接的正是「query」查询字串,其组成通常是一对 key 和 value,假设一段网址最後为「?search=java&user=john」(多组 query 中间以 & 串连) ,则透过 $route.query 便能取得 query 物件的内容为 {search: 'java', user: 'john'}

知道方法之後,实际应用在我们的专案范例上:

  • 原本在 <BookList> 元件上监听的 input 事件是将输入值直接赋值给 inputText prop,再传递给子元件渲染在 input 上;由於要在监听事件增加其他执行内容,因此可改为监听 methods 中的函式 searchBookName

    <div class="All">
      <BookList
        navTitle="All"
        :bookList="books"
        :inputText="searchText"
        @searchBook="searchBookName($event)"
      />
      <!-- 原先写法:@searchBook="searchText = $event.target.value" -->
    </div>
    
  • searchBookName函式除了原本的赋值工作,另外追加设置 $router.replace,让每次即时输入字串的同时,都会将输入值列入 query 物件中,并且更新 key 为 search 的 value 内容,於是每当输入字串的同时,都会重新导向连动输入字串的 query 路径。

    methods: {
      searchBookName(event) {
        this.searchText = event.target.value;
        this.$router.replace({
          name: this.$route.name,
          query: { search: event.target.value },
        });
      },
    },
    
  • 接着在元件内使用的导航守卫 beforeRouteEnter 进行判断,当路径带有指定 key 为 search 的 query 物件时,要先将 search 对应的 value 赋值给 searchText,透过 inputText prop 传给子元件,因此当重新整理页面时,赶在画面渲染好之前,已经将重整页面之前的搜寻值再次渲染至 input 栏位中了。

    这边需要留意的是,beforeRouteEnter 阶段无法取得 this,因为其会在导航确认之前被调用,当时准备进入的元件实例的尚未完成创建,不过可以在 next callback 中透过 vm 取得实例,再利用 to 取得目标路由物件中的 query 物件。

    beforeRouteEnter(to, from, next) {
      next((vm) => {
        if (to.query.search) {
          vm.searchText = to.query.search;
        }
      });
    },
    
    data() {
      return {
        searchText: "",
      };
    },
    

设置完成後,测试看看在搜寻栏输入「vue」,检查一下以下三种情境,无误的话就代表成功了!

  1. 网址变成「http://localhost:8080/book/all?search=vue
  2. 重新整理页面後,会再显示同样的搜寻结果
  3. 切换至其他路由後,再按返回上一页或前往下一页,都能再次显示同样的搜寻结果
    query

$router.replace VS $router.push

简单说明两者的差别在於 $router.replace 不会向 history 留下纪录。以上述范例为例,若使用 $router.push,则当我输入「java」之後,按下返回上一页,会使路径变成「 http://localhost:8080/book/all?search=jav 」;而使用 $router.replace 的话,上一页会是进入当前路由的上一个页面。

相关实作也可以应用在登入流程,假设一个使用者的动线是从首页进入会员登入页,若登入成功之後应该透过 $router.replace 将他导向会员後台,此时他若想要返回上一页,就会因为在登入页没有留下 history 纪录,而跳过登入页又再次回到一开始的进入点首页,因为对一个登入成功的使用者来说,不适合以登入状态能够再次回到登入页。

参考资料


<<:  23 - Prettier - 格式化程序码工具

>>:  Day24 类别与物件--魔术方法3、trait

【DAY 17】微软生产力平台 Microsoft Power Platform 补充 — Code 与 No-Code

【DAY 17】微软生产力平台 Microsoft Power Platform 补充 — Code...

事件监听的this:「这个」到底是哪一个?

欧阳克是谁杀的? 这个this是谁?要看凶手是谁而定! 前面有提到,这个e是在当事件发生时,事件处...

[Android 开发经验三十天]D29一小画家小问题跟改善方法

职涯在走,铁人赛文章一定要有。 小画家小问题跟改善方法 tags: 铁人赛 嗨,大家安安,今天来说...

[Day 24] 阿嬷都看得懂的响应式网页设计在干嘛

阿嬷都看得懂的响应式网页设计在干嘛 还记得前两天我们在玩贴纸簿的时候,问过这个问题:我们的整个网页到...

Chapter1-DJ最爱的音频动感图像(IV)让音乐动起来!开篇基础设定和动画框架

话不多说先上图 从左到右依序执行,最後该函式会再呼叫自己一次,图中淡化的区块是下个章节的主题 然後把...