前端开发:Vue以及Vue的路由
Vue是什么
警告:本文作者是底层程序员,对Vue只是偶尔用到,研究并不深入,对Vue的理解可能非常肤浅甚至存在错误,请多包含。以下文字只为外行记录分享,专业前端朋友可以略过。
作为一个底层老程序员,比如经常写驱动或者内核的,再不济也像我这样整天跟Epoll、Socket打交道的老家伙,可能对Vue的那一大套东西,有点儿陌生。
甚至,可能会有点儿疑惑,有Java、PHP、Python、go、Rust等一大票后端语言,有HTTP协议交换数据,有HTML负责显示,有CSS渲染参数,还有JavaScript在浏览器里动态执行,还要Vue这种东西干什么呢?
按照我的理解就是,虽然以上这些技术已经足够完成Web开发了,但是对于纯前端来说,工程化的程度并不够。
比如,HTML里面已经定义好了各种组件,比如输入框、文本框、单选按钮等等,但是问题也就在这里,即HTML不支持自定义组件。或者说,支持自定义组件,但是并不容易。很多开发团队使用HTML+CSS+JavaScript实现了自己的组件,但是被其它团队开箱即用。
再比如,虽然JavaScript足够灵活,但是是语言层面的。即JavaScript支持各种语言特性,但是这些语言特性,跟真正的前端结合起来,就需要CSS、HTML等东西的配合,另外很多跟浏览器还强相关。
所以,就有了Vue这种更工程化的库(我是这么理解的)。
使用Vue,可以方便地定义一些前端组件,其它团队只要引入Vue的这些组件,就可以像Java、Python的包一样引入,像Rust的crate一样开箱即用。
Vue的Router
Vue可以支持单页面应用。即整个项目就在一个大的首页里面,所有的跳转都在这个首页里面,所有的操作观感,就类似于通过Ajax技术,不断地拖动地图应用里面的地址,放大缩小,前前后后。
对于开发来说,就不需要再写HTML,只需要写Vue就好。在Vue里面,把一些动作指向不同的组件,跳来跳去。
而这种跳转,就可以通过Router来做。
其实,很多后端语言里面,都是通过把URL集合做成路由的,前端语言也采取了这种设定。
使用Vue的Router需要安装vue-router,之后使用CreateRouter方法。
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'hash',
routes: [
{
path: '/login',
name: 'login',
component: login
},
{
path: '/logout',
name: 'logout',
component: logout
}
]
})
上面的代码就是,/login就会跳转到login组件,/logout就会跳转到logout组件。
Router的两种mode
需要注意的是,Router的mode选项有两种。
一种是上面设置的hash,这种mode的url会加上#。即,如果我们部署在http://test.com网站,那么我们的登录页url将会是http://test.com/#login。
这样的好处是,当我们在网页中打开http://test.com/#login之后,刷新页面的时候,仍然会向Web服务器请求/,然后通过本地的Vue代码,跳转到#login页面。
如果我们使用的是另一种mode,即history,跳转的url会是http://test.com/login,这样如果我们刷新页面,浏览器就会向Web服务器请求http://test.com/login。默认情况下,我们的服务器解析不了这个url,会返回404。
为了让这种模式工作,我们需要在Web服务器上,配置/login到/,有多少就需要配置多少。当然也可以使用正则表达式,把所有相关的url都重定向到/,但是这样的问题是,有些真正需要服务端处理的url,就也被重定向了。在使用中,需要根据具体业务,灵活配置。
比如,如果在Django中,就可以在urls.py文件里使用re_path来添加:
urlpatterns = [
# admin url
path('admin/', admin.site.urls),
# vue url
path('', TemplateView.as_view(template_name="index.html")),
# 正则表达式满足login、logou
re_path('/log.*', TemplateView.as_view(template_name="index.html"))
]
Router的动态匹配
Vue的Router也支持动态匹配,只要在url字段里加入:即可。
如:
export default new Router({
mode: 'hash',
routes: [
{
path: '/user/:id',
name: 'user',
component: User
}
]
})
之后类似 /user/a、/user/b、/usr/cdlkafdjkl 等这样的url都会映射到User组件上。
当一个路由被匹配时,值将在每个组件中以 route.params 的形式暴露出来。因此,我们可以通过User 的模板来呈现当前的id:
<template>
<div>
User {{ $route.params.id }}
</div>
</template>
另外,Router也支持多个参数,只要每个都以:开头,之后就可以在router.params里访问了,非常方便。
Vue的Router的组件复用问题
当使用了动态匹配之后,当连续进入同一个组件的时候,Vue就不会刷新组件了。我们为了更改其中动态的页面部分,需要在回调里面,实现动态更改组件的逻辑。
如:
export default {
beforeRouteEnter (to, from, next) {
console.log('beforeRouteEnter: ' + to.path)
next(vm => {
vm.urlChanged(to);
})
},
beforeRouteUpdate (to) {
console.log('beforeRouteUpdate: ' + to.path)
this.urlChanged(to);
next()
},
}
**一定注意beforeRouteUpdate回调函数中,最后要加上next调用,这样Router的回调链才能继续下去。
NavigationDuplicated
重复打开同样的url,Vue-Router会拒绝执行,终端返回一个错误:
Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: ......
不影响使用。
但是,如果想关闭这个错误记录,也是可以的。即覆写一下Router的push方法,在错误回调中,把这种错误信息过滤掉。
const originalPush = Router.prototype.push
Router.prototype.push = function (location) {
originalPush.call(this, location).catch((err) => {
if (err.name !== 'NavigationDuplicated') {
console.trace(err)
}
})
}