简介:
想要通过ES6的Import特性,再加上正则表达式匹配当前url地址的方式来做单页应用。
碰到的问题
1,在html中直接引入 js 代码,代码使用了import会直接报错?
因为浏览器在加载 script 标签的时候,默认的脚本类型是type="text/javascript"。而这种类型是不支持es6的。
所以,想要使用es6的方式,需要使用 type="module"的方式,这种方式会让我们的脚本代码形成独立的作用域,并且可以使用es6的特性 import。
<script type="module" src="../index.js"></script>
2,使用了 type='module'方式来引用脚本代码,但是会遇到跨域的问题。
解决方式:
- 本地启动node服务,通过服务的方式来解决脚本的跨域请求稳定。
- 模块引入方式
<script type="module" src="http:xxx/index.js"></script>
3,import 的局限?
想要通过 ES6 中的 import 语法来加载本地的资源文件(html, js, css),但是发现 import 的机制是在编译时运行,并且需要在代码的头部引入。当我们想要在代码运行中的时候就无法使用这个方式(比如,从A页面切换到B页面,就需要在项目运行中加载B页面的资源)。
解决方式:
把 ES6的 import 方式改为 seajs 。
4,seajs 的重新加载的问题?
由 ES6的 import 方式改为 seajs 后,发现在销毁页面的时候(从A页面到B页面,想要销毁A页面的js和css,如不销毁,从B页面再到A页面的时候,A页面的js会无效,具体是指模版重新加载,但是js没有会造成事件的无效监听),我删除了之前通过 require.async() 引入的静态文件,等页面再回来的时候,无法重新加载A页面的静态资源了??不知道vue-router如何处理的?
解决方式:
seajs为了避免已经加载的资源重复加载,从而造成性能的问题,就会把已经加载的资源进行缓存。我们通过修改 seajs的源码,删除缓存即可。
简单的路由控制器
先来讲下整体的思路,首先需要一个路由配置文件,然后通过监听url的变动,获取到当前路由的信息。再根据路由信息加载不同页面所需要的各种资源并执行。
整体文件结构如下:

可以看出,使用node起的服务器,因为我们在使用seajs加载组件的html(模版)的时候,借助于XMLHttpRequest来加载,所以需要启动服务进行访问。
我们主要讲下public目录下代码。
- pages 是各个不同页面的代码,其中包含了登录页面和欢迎页面,每个页面里都有html文件,js文件和css文件。
- script 是整个项目的执行代码目录
- script/lib 里包含了 seajs 代码和自己的工具代码
- script/main.js 是逻辑主代码
- script/router.config.js 是路由的配置文件
- index.html 是单页应用根文件,所有的组件都会在这里切换加载。
1,根页面

根页面主要是创建一个容器,并且引入seajs,通过seajs来执行我们的逻辑主代码
2,路由配置
define((require, exprots, module) => {
var routersConfig = [{
name: 'login',
path: '/user/login',
component: 'pages/login'
},{
name: 'welcome',
path: '/welcome',
component: 'pages/welcome'
},{
name: '',
path: '/',
redirect: '/welcome'
}]
module.exports = routersConfig;
})
以上是路由配置文件,既然,我们使用seajs,就需要按照seajs的代码规范来写。开发过微信小程序的小伙伴们应该比较熟悉这种组织方式,路由定义了基本的四个要素。
- name 用于区别每项路由信息
- path 路由的url地址,当url改变的时候,我们使用这个来匹配是当前路由
- compoent 每个路由的组件地址,以 public 目录为起点来书写。
- redirect 路由跳转地址,当某个路由和其他路由的组件共用,可以使用。
3,主逻辑代码
const current_url = window.location;
// 如果hash值是空,就跳转到路由配置中设置的默认路由
const hash = current_url.hash;
if (hash == ""){
const {path} = getDefaultRouterPath();
_redirect(path);
} else {
const {component} = getRouter(hash);
realodPageComponent(component);
}
// 首先默认当作是hash模式,监听hash部分的路由
window.addEventListener("hashchange", (origin)=>{
const {newURL, oldURL} = origin;
const newUrlHash = _getHashByUrl(newURL);
const oldUrlHash = _getHashByUrl(oldURL);
// 卸载老的页面
const {component: oldComponent} = getRouter(oldUrlHash);
destoryPageComponent(oldComponent);
// 加载新页面
const {component} = getRouter(newUrlHash);
realodPageComponent(component);
console.log('hashChange', origin)
},false);
主逻辑的代码也很清晰,主要有两部分:第一部分,就是当代码执行的时候,我们先获取到当前路由的hash值,如果没有hash,就在路由配置中找到默认路由并加载组建,如果找到了hash值,就加载hash值对应的路由组建。(注意,我在这里默认使用hash模式来搭建单页应用)。当然,如果有hash值,但是没有找到对应的路由信息,我们可以跳转到 404 页面。第二部分,监听页面hash的变化,获取到新路由hash 和 老路由hash值,然后去卸载 老路由的组件。加载新路由组件。
4,后续
其他具体实现代码,我就不一一讲了,感兴趣的同学可以通过(https://e.coding.net/dtid_0a0723508d7ccdd6/jny-subject/jny-router.git)访问。当然只是路由的初期,后面还需要继续完善,比如,我们需要二级页面,需要404,需要 history 模式,需要路由等等。
网友评论