使用 VueRouter 构建SPA单面应用DEMO
H5页面使用 VueRouter 构建SPA单面应用DEMO
VueRouter 实现原理
一个页面地址由协议/主机名/页面地址/查询字符串/hash组成,如
https://www.host.com/static/index.html?query=123#/user/110
通过浏览器打印以下变量可知道
location.href "https://www.host.com/static/index.html?query=123#/user/110"
location.search "?query=123"
location.hash "#/user/110"
通过给 location.href 一个新地址,页面就会刷新跳到指定的地址上,这相当点击一个超链接进入新页面。但是,如果新地址只有hash这部分不同,其它都一样的情况就不同了。地址整体是有变化的,但页面不会刷新跳转。通过脚本可以检测到这种变化,那将这种变化以一定的规则和需要呈现的视图绑定,这就是VueRouter干的事。例如,点击这样一个VueRouter路由链接:
<router-link to="/user/110">Go to User</router-link>
浏览器地址栏就会改变hash部分:
#/user/110
DEMO 展示要点
-
VueRouter 的基本使用方法
-
命名路由,在路由配置项中使用了 name 属性,如 {path: '/user/:userId', name: 'user', component: User }
-
嵌套路由,通过 children 给路由配置子级路由项目
-
重定向路由配置项 { path: '/a', redirect: '/b' } 或在 redirect 中使用命名路由 { name: 'foo' },或一个方法动态返回重定向目标的方法
-
路由出口组件即生成视图路由结果的视图,<router-view></router-view>
-
命名视图 <router-view name="specialView"></router-view>,不设置name属性,默认值为 default
-
多视图路由配置 {path: '/', components: { default: Foo, specialView: User } }
-
<router-link> 路由组件会渲染成a标签,点击 <router-link :to="..."> 等同于调用 router.push(...)。
-
<router-link> 使用命名路由 <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
-
编程式的导航
router.go(n) 类似 window.history.go(n)。
router.push(location, onComplete?, onAbort?)
router.replace(location, onComplete?, onAbort?) 相当声明式 <router-link :to="..." replace>router.push('home') // 字符串
router.push({ path: 'home' }) // 对象
router.push({ name: 'user', params: { userId: 123 }}) // 命名的路由
router.push({ path: 'register', query: { plan: 'private' }}) // 带查询参数,变成 /register?plan=private
关于路由嵌套参考
https://router.vuejs.org/zh/guide/essentials/nested-routes.html
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<style>
.button { padding:2px; text-decoration: none; background:#00CAFF; border:1px solid #cccccc;}
.button:hover {color:#fff;}
.router-link-active {background:#FfBb00;}
</style>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航,它会被渲染成一个 `<a>` 标签,`to` 属性指定链接 -->
<!-- IE天生天然残缺,不支持反引号,`/user/${id}/${name}`这样的模板字符串就不能使用了 -->
<router-link class="button" to="/foo">Go to Foo</router-link>
<router-link class="button" to="/bar">Go to Bar</router-link>
<router-link class="button" :to="'/user/'+id+'/'+name">Go to User1 View</router-link>
<router-link class="button" :to="'/user/112/Jimbo'">Go to User2 View</router-link>
<button class="button" @click="goBack">Go Back</button>
<span>Watching {{stamp}}</span>
</p>
<!-- 路由视图 路由出口 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
<!-- 命名视图 -->
<router-view name="secondary"></router-view>
</div>
<script>
// 1. 定义组件。组件也可以通过 Vue.extend() 创建或者是一个组件配置对象
const Foo = { template: '<div>foo view</div>' }
const Bar = { template: '<div>bar view</div>' }
const User = {
template:'<div>' + // 因为组件模板只能有一个顶级元素所以这里要使用div包裹两个子元素
' <div>Hello {{ $route.params.id }}</div>' +
' <router-view></router-view>' + // 组件中使用路由视图用于渲染子路由匹配到的组件
'</div>',
watch: { // 添加 watch 方法对路由变化作出响应...
$route:function (to, from) {
console.log("route change ",to," <= ",from);
this.name = to+" <= "+from;
}
},
beforeRouteEnter:function (to, from, next) { // to, from 都是 $route 实例
console.log("before route enter ", to, " <= ", from);
next();
},
beforeRouteUpdate:function (to, from, next) { // 2.2 中引入的导航守卫
// react to route changes...
// don't forget to call next()
console.log("before route update ", to, " <= ", from);
next();
}
}
// 2. 配置组件的路由,每个路由应该映射一个组件
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar, name:"toBar" }, // 设置 name 属性来配置一个命名路由
{ path: '/user/:id', component: User, // 动态路径参数 以冒号开头
children:[ // 嵌套路由 子视图内容会渲染到 User 组件中的 <router-view></router-view>
{ path:'', component:User }, // 子路由空路径时匹配上一级路由 /user/:id
{ path:'jeango', component:Foo }, // 匹配 /user/:id/jeango
{ path:'jimbo', component:Bar }
]
}
]
// 3. 以 `routes` 配置创建 router 实例,{ routes } 是ES6缩写,相当于 {routes: routes}
const router = new VueRouter({ routes:routes })
// 4. 创建vue实例和挂载根实例。启动应用!
const app = new Vue({
router:router,
data:{name:"Jeango", id:110, stamp: + new Date()},
watch: { // 监视参数变化
stamp:function () {
console.log('watching', this.$route);
return this.$route.params.name
}
},
methods: {
goBack:function () {
this.stamp = +new Date(); // 更新相间数据触发watch事件
window.history.length > 1
? this.$router.go(-1)
: this.$router.push('/')
}
}
}).$mount('#app')
</script>