Laravel5与前端(二)单页与懒加载

接上一篇:Laravel5与前端(一)快速上手

单页 vs 多页

熟悉前端的同学也许听过 SPA(single page web application,单页Web应用),它究竟是个什么东西呢?

前段路由

app.js(入口) 文件只有一个,页面间的路由放在前端完成。而多页应用需要每个页面对应一个app.js,路由是放在后端来实现的。

更少的HTTP请求

不用像多页应用那样,每一个页面都需要HTTP请求,单页应用由于后端路由只有一个,所以HTTP请求较少。而多页应用的页面和页面内的资源文件每次都需要重新请求,这样对HTTP压力较大(缓存压力也大)。

更快的响应

在SPA中进行页面切换时,没有白屏期,用户使用更加流畅。

更注重分离

后端只需提供数据即可,无需计算页面展示逻辑和合成页面,这样以来后端更加专注数据处理,前端更加注重交互处理。

vue-router

vue-router可以轻松的实现前端路由功能,它是配合vue一起使用的。

安装

使用npm安装:

1
npm install vue-router -S

app.js 中引入:

1
2
3
4
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

开始使用

html:

1
2
3
4
5
6
7
8
9
10
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>

app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]

const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})

// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')

上述代码定义了2个前端路由页面,各行代码的作用如下:

1-2行:定义了两个页面 FooBar

4-7行:配置这俩页面到路由 /foo/bar

9-11行:实例化VueRouter对象

15-17行:实例化Vue对象并挂载到 #app 元素上,同时注入router

在线演示:https://codepen.io/JerryCheese/pen/xWrebL

关于更多vue-router使用方法,参见官方教程:https://router.vuejs.org/zh-cn/

模块化 vs 组件化

多页应用中的 实际上指的就是一个个 .html 文件,在单页应用中不同的内容称为 模块 对应一个一个 .vue 文件。例如下面两个模块,表示两个不同的管理页面:

modules/User.vue 文件:

1
2
3
4
5
<template>
<div>
<h3>用户管理</h3>
</div>
</template>

modules/Course.vue 文件:

1
2
3
4
5
<template>
<div>
<h3>课程管理</h3>
</div>
</template>

app.js 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Vue from 'vue'
import VueRouter from 'vue-router'
import UserPage from './modules/User'
import CoursePage from './modules/Course'

Vue.use(VueRouter)

const routes = [
{ path: '/user', component: UserPage },
{ path: '/course', component: CoursePage }
]

const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})

const app = new Vue({
el: '#app',
router
});

html:

1
2
3
4
5
6
7
8
9
10
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/user">用户管理</router-link>
<router-link to="/course">课程管理</router-link>
</p>
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>

这样一来,每个模块(或者说页面)对应到了一个 .vue 文件。从代码本质上来说,他们都是vue组件,只是为了便于区分而取了名字而已。

懒加载

现在我们知道了,单页应用通过js调用来显示不同的页面内容,也叫做模块。

现在的问题是,当页面数量很多时,它们会被打包进一个app.js文件中,这会导致这个文件非常大,那么在用户首次访问时会占用大量HTTP资源。

用户也许只看其中的一两个模块而已,有没有方法可以让模块按需加载而不是一次性都加载呢?答案就是懒加载。

所幸vue-router支持懒加载功能,所以我们不必自己基于Webpack的代码分割功能来自己实现了。

懒加载一个模块

我们看这段代码:

1
2
3
4
5
6
7
8
9
...
import UserPage from './modules/User'
import CoursePage from './modules/Course'
...
const routes = [
{ path: '/user', component: UserPage },
{ path: '/course', component: CoursePage }
]
...

它引入了两个模块,并且直接配置到了routes的component中,如果要懒加载,怎么做呢?改成下面这样就行:

1
2
3
4
5
6
7
8
9
10
11
...
//import UserPage from './modules/User'
//import CoursePage from './modules/Course'
const UserPage = () => import('./modules/User')
const CoursePage = () => import('./modules/Course')
...
const routes = [
{ path: '/user', component: UserPage },
{ path: '/course', component: CoursePage }
]
...

如果报错的话,那是因为babel不能正确解析异步语法 () => import,需要安装syntax-dynamic-import

1
npm install --save-dev babel-plugin-syntax-dynamic-import

并且在webpack.mix.js同目录处新建文件 .babelrc,输入以下配置信息:

1
2
3
{
"plugins": ["syntax-dynamic-import"]
}

完成之后,打开页面,访问路由,发现:

这俩文件其实就是前边定义的俩模块对应的js,在访问到它们时,它们的js才会被加载,也就是所谓的懒加载啦。

更改懒加载文件目录

默认情况下,上述的 0.js1.js 是在根目录的,这样对目录结构很不友好,我们希望把它们放在一个特定的目录去,在 webpack.mix.js 中添加:

1
2
3
4
5
6
mix.webpackConfig({
output: {
publicPath: "/",
chunkFilename: 'js/lazy/[name].[chunkhash].js'
},
})

这样的话,懒加载的js文件会放到 /js/lazy 目录中去,而不是在 / 中。

总结

单页应用写起来非常爽(私以为)

坚持原创文章分享,您的支持将鼓励我继续创作!