引言

众所周知,Web 系统的早期路由是由后端来实现的,服务器根据 URL 来重新加载整个页面。这种做法用户体验不但不好,而且页面若是变得复杂,服务器端的压力也会随之变大。随着 Ajax 的广泛应用,页面能够做到无需刷新浏览器也可更新数据,这也给单页应用和前端路由的出现奠定了基础。因此,在单页应用系统中使用前端路由也十分常见,很多前端框架也提供或者推荐配套使用的路由系统。san-router 是 San 框架的官方 router,以方便用户基于 san 构建单页或同构应用为目标。本文也主要来说明实践过程中如何使用 san-router 来构建一个单页面后台管理系统。

路由配置

使用 san-router 和 San 构建单页应用的系统主要基于路由和组件。路由处理放在浏览器端来直接响应浏览器地址的变换,分发到对应的路由。在路由发生变化时,通过加载相应的组件,替换需要改变的部分,来向用户呈现对应的界面。所以路由配置是比较关键的一步。

单页应用系统中应该创建一个入口 js 文件(如 main.js ),在其中可以配置相关路由,attach 一个根组件,并将路由的 target 设置为根组件中的标签:

  1. // main.js
  2. import san from 'san';
  3. import {router} from 'san-router';
  4. import App from './App.san';
  5. // attach 根组件 App
  6. new App().attach(document.getElementById('app'));
  7. // 路由规则
  8. const routes = [
  9. {
  10. rule: '/',
  11. Component: Home
  12. },
  13. {
  14. rule: '/list',
  15. Component: List
  16. },
  17. {
  18. rule: '/about',
  19. Component: About
  20. }
  21. ];
  22. // 将路由规则的 target 属性设置为根组件中的标签
  23. routes.forEach(item => {
  24. router.add({
  25. ...item,
  26. target: '#main'
  27. });
  28. });
  29. // 设置路由模式 'html5 | hash'
  30. router.setMode('html5');
  31. // 设置路由监听
  32. router.listen((e, config) => {
  33. // 在路由发生变化时触发
  34. console.log(e);
  35. console.log(config);
  36. });
  37. // 启动路由
  38. router.start();

在路由规则配置过程中,通过调用 router.add({Object}options) 来添加路由规则,在 options 对象中指定 Component 和 target 参数。将特定的 URL 规则映射到相应的组件类上,在 URL 变化并匹配路由规则时,将对应逻辑子组件初始化并渲染到页面中。

san-router 有两种路由规则配置:
rule 为 string 时,URL 的 path 部分与字符串完全匹配才可
rule 为 RegExp (正则)时,URL 的 path 部分与该正则部分匹配即可

路由规则配置完成后,可以通过调用 setMode 方法来设置路由模式,通过调用 listen 方法来添加路由监听器,当发生路由行为时被触发。

最后,可通过调用 start 方法来启动路由,根据 URL 的变化来匹配规则,渲染相应的组件到界面上。

App根组件

App 作为根组件,布局了整个系统界面不需要更新的部分,搭建出了系统界面基本的骨架。那些需要更新的部分则是在 App 组件被附加到页面后,通过启动路由,来加载不同的逻辑组件,渲染到路由规则 target 属性对应的标签里:

  1. // App.san
  2. // Link 组件
  3. import {Link} from 'san-router';
  4. // App Component
  5. class App extends san.Component {
  6. static components = {
  7. 'router-link': Link
  8. };
  9. static template = `
  10. <div class="app-container">
  11. <div class="app-drawer">
  12. <div class="drawer-title">
  13. <h3>XXX管理系统</h3>
  14. </div>
  15. <div class="menu">
  16. <ul>
  17. <li><router-link to="/">Home</router-link></li>
  18. <li><router-link to="/list">List</router-link></li>
  19. <li><router-link to="/about">about</router-link></li>
  20. </ul>
  21. </div>
  22. </div>
  23. <div class="app-bar">
  24. <div class="user-info">
  25. <span>userName</span>
  26. </div>
  27. </div>
  28. <div class="app-content">
  29. <!-- 逻辑组件渲染处 -->
  30. <div id="main"></div>
  31. </div>
  32. </div>
  33. `;
  34. }

逻辑子组件

逻辑子组件是指根据路由匹配规则渲染到页面中的业务逻辑组件。这些组件按照业务逻辑,由基础组件库中的组件组装而成,在匹配到对应路由时,进行初始化和渲染。

逻辑子组件是正规的 san 组件,每一个逻辑子组件可以放在一个单独的文件里,调用基本组件库来组装而成,设置在不同生命周期阶段想要处理的业务:

  1. // About.san
  2. class About extends san.Component {
  3. static template = `
  4. <p>关于关于</p>
  5. `;
  6. initData() {
  7. return {};
  8. }
  9. route() {}
  10. attached() {}
  11. }
  12. // List.san
  13. class List extends san.Component {
  14. static template = `
  15. <p>list,list</p>
  16. `;
  17. initData() {
  18. return {};
  19. }
  20. route() {}
  21. attached() {}
  22. }
  23. // Home.san
  24. class Home extends san.Component {
  25. static template = `
  26. <p>Home</p>
  27. `;
  28. initData() {
  29. return {};
  30. }
  31. route() {}
  32. attached() {}
  33. }

总结

使用 san-router 构建一个单页应用后台系统的关键点在路由配置、根组件和逻辑子组件三个方面,如果能优雅地做好以上三个方面,就能在后期开发与扩展过程中复用组件和模块,提高开发效率。另外,单页应用基于前端路由、组件化思想和前端数据流方案。因此,在构建一个单页应用系统时,还需关注前端数据流管理,对于业务比较复杂多变的后台管理系统,复用组件、有效管理 Ajax 请求和前端数据流有利于提高开发和维护效率。所以单页应用在实践中也被广泛应用,但是每种技术方案有其局限性,单页应用要在一个页面上提供所有功能,首次需要加载大量资源,资源加载时间也相对较长,在选择技术方案时还需要兼顾具体应用场景。

示例

See the Pen san-router-spa by sqliang (@sqliang) on CodePen.