Day32 | 在WebView里使用Router的问题与解法!

大家好,今天是第三十二天,也是赛程结束後的第二天。

昨天介绍了我们会在Webview里使用的套件,今天会介绍一下在webview里使用router时实际遇到的问题与解决方法。并会以专案的情境做个示范,最後附上解决问题时参考的一些资源。

在Webview中使用Router时可能遇到的问题


前面Webview的章节提过了,在vscode里面使用javascript跟存取静态资源(本地的png、svg等等),会受到限制。
除此之外,我们没办法给定Webview本身存取html的url。因此,在使用一些正常使用router library的状况,router并不会作用。

让我们先使用react router的来做个示范。

首先,让我们使用React Router,创建简单的RouterPage元件。

RouterPage.tsx:

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useHistory,
} from "react-router-dom";

export default function RouterPage() {
  return (
    <Router>
      <div>
        <h1>With Browser Router</h1>
        <nav>
          <ul>
            <li><Link to="/snippets">snippets</Link></li>
            <li><Link to="/extensions">extensions</Link></li>
          </ul>
        </nav>
        <Switch>
          <Route path="/snippets">
            <Snippets />
          </Route>
          <Route path="/extensions">
            <Extensions />
          </Route>
          <Route path="/">
            <Snippets />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Snippets() {
  const history = useHistory();
  return <h2 onClick={()=> history.push('/extensions')}>Snippets</h2>;
}

function Extensions() {
  const history = useHistory();
  return <h2 onClick={()=> history.push('/')}>Extensions</h2>;
}

依我们的需求,我们应该要有两个页面分别负责自订的snippet与第三方extension的管理,因此我们在上面简单宣告Snippets与Extensions的component,并设定导航的路由。同时,我们在component上绑定点击事件,在点击当下的页面後就让即跳转到另一个component上。

完成RouterPage後,我们将其import於App.tsx中给上层的App元件使用

import RouterPage from './router/router';
...
function App() {
  return (
    <RouterPage/>
  );

配置好WebviewPanel的相关设定後,我们启动extension查看结果,可以看到页面,并显示了Snippets元件。

我们改换点击extensions的超连结

可以看到,并不会起作用。

BrowserRouter是使用浏览器Html5的History,他在改变url时,会与vscode的url格式起冲突,因此我们会在Webview Devtool下面看到这样的错误讯息。

好的,那要怎麽避免这个状况呢?

解决方法


  • 解法一: 使用MemoryRouter

在React Router里面,提供了一种MemoryRouter,在不读写浏览器的网址列的状况下导航页面,通常是用於测试与React native非浏览器的环境。MemoryRouter可以直接规避这个问题,让我们先将import的BrowserRouter改为MemoryRouter,并将With Browser Router的标题改为With Memory Router。

import {
  useHistory,
  MemoryRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

接下来我们一样使用yarn build(或npm run build)指令,再重新载入webview。

现在我们点击超连结,就可以顺利切换元件,点击元件也可以正常触发效果。

Webview Devtool现在也不会有任何错误讯息。

  • 解法二: 使用HashRouter

在网址列里的Hash是一个#符号,指示浏览器要滑动到的位置。例如:

https://stackoverflow.com/questions/31079081/programmatically-navigate-using-react-router/31079244#31079244

点击下去後,浏览器就会自动滑到编号是31079244的回答的位置。

hash符号主要与浏览器端的行为有关,因此,在浏览器将网址请求发送到後端时,通常hash符号会被忽略,不会将hash符号一起送至後端。

我们可以在chrome的devtool里很清楚的看到上面网址输下後的请求会被自动忽略掉#31079244。

除此之外,hash位置改变时,会被浏览器的history记录起来,因此在刚才输入网址後,我们可以按上一步回到没有hash值的同网页。也因为有这个特性,hash值很适合用於处理router的动作,react router也提供了HashRouter让我们使用。

现在,让我们将上面范例里的Router改为HashRouter验证是否正常吧!

import {
  ...
  HashRouter as Router,
  ...
} from "react-router-dom";

重新载入Webview後,可以确认HashRouter一样可以在Webview里正常运作。

结语


好的,以上就是我们今天分享的内容。在处理router问题的解法上,笔者事先参考了How to use React Routing into Webview for VSCode extensions?这篇文章跟stackoverflow上的回答解法,主要介绍了MemoryRouter来避免Webview里的router问题。

在实际测试後,我们也可以验证HashRouter会运作正常,推测原因是hash值会自动被WebView浏览器请求所忽略,因此也就不会请求不一样的url位置触发错误。

明天我们继续实作,我们明天见,掰掰!

参考资料



<<:  [Day32] 第三十二课 Azure资讯安全中心-2

>>:  32.Module2

DAY27-Firebase Domain设定

前言: 昨天跟大家介绍了如何把你写好的网页透过firebase deploy到网路上,但目前还只能透...

模型架构--4

Facenet 是google在2015於CVPR所发表的,提出在特徵空间里做出识别、验证的问题,只...

英雄列表范例:载入资料

接下来我要用一个小应用来介绍基本的 CRUD 实作:复仇者英雄列表。它的功能如下: 新增英雄到列表中...

Day10 Scanner(Ⅱ)

Scanner 常使用到的Methods 整数 nextInt() 2.小数 nextDouble(...