为 Vue Router 添加页面布局
Laravel 可以通过 Blade 模板为应用添加页面布局,不过由于我们构建的是单页面应用,可以通过 Vue Router 来实现:创建一个根级页面,其中包含在每个页面都会用到的 Vue 组件,如 Header 和 Footer。使用布局的另一个好处是你可以一次加载所有你需要的 Vuex 数据,它们会随着布局里的组件出现在所有子页面上。
第一步:重新组织嵌套路由
在设置前端路由那篇教程中,我们并没有包含嵌套路由,而 Vue Router 的路由嵌套正是可以用于创建布局的小技巧,更多关于嵌套路由的细节,可以查看官方文档。
首先,我们需要构建一个顶级路由作为布局,将路由文件 resources/assets/js/routes.js
中原来定义的路由删除,添加这段路由定义:
{
path: '/',
name: 'layout',
component: Vue.component( 'Home', require( './pages/Layout.vue' ) ),
},
Layout.vue
布局文件将在下一步添加,现在我们继续编辑这个路由文件,我们上面定义的是一个顶级根路由,接下来我们要把原来的路由作为嵌套路由放到名为 children
的配置数组中:
export default new VueRouter({
routes: [
{
path: '/',
name: 'layout',
component: Vue.component( 'Home', require( './pages/Layout.vue' ) ),
children: [
{
path: 'home',
name: 'home',
component: Vue.component( 'Home', require( './pages/Home.vue' ) )
},
{
path: 'cafes',
name: 'cafes',
component: Vue.component( 'Cafes', require( './pages/Cafes.vue' ) ),
},
{
path: 'cafes/new',
name: 'newcafe',
component: Vue.component( 'NewCafe', require( './pages/NewCafe.vue' ) )
},
{
path: 'cafes/:id',
name: 'cafe',
component: Vue.component( 'Cafe', require( './pages/Cafe.vue' ) )
}
]
}
]
});
接下来我们来添加 Layout.vue
页面。
第二步:添加 Layout.vue
在 resources/assets/js/pages
目录中创建 Layout.vue
作为我们的布局文件,编辑文件内容如下:
<style>
</style>
<template>
<div id="app-layout">
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<router-view></router-view>
组件将用于渲染导入父组件的子组件。
有了布局之后,就可以导入在上一篇教程创建的 Navigation.vue
公共组件了,我们需要在导出默认组件之前导入组件,并在导出组件的 components
配置对象中告诉页面使用这个导入的组件:
<script>
import Navigation from '../components/global/Navigation.vue';
export default {
components: {
Navigation
}
}
</script>
最后,我们将这个组件添加到页面模板中:
<style>
</style>
<template>
<div id="app-layout">
<navigation></navigation>
<router-view></router-view>
</div>
</template>
<script>
import Navigation from '../components/global/Navigation.vue';
export default {
components: {
Navigation
}
}
</script>
这样,Navigation
组件就会出现在所有页面中,因为每一个页面都是布局的子页面。
下面我们在所有页面上加载数据,由于我们已经在构建 Vuex 模块教程中构建好了相关 Vuex 模块,所以只需要将其绑定布局页面的 created()
钩子函数并加载响应数据即可。在本案例中,我们需要在导航组件中显示用户信息以及咖啡店列表信息,所以最终的 Layout.vue
代码如下:
<style>
</style>
<template>
<div id="app-layout">
<navigation></navigation>
<router-view></router-view>
</div>
</template>
<script>
import Navigation from '../components/global/Navigation.vue';
export default {
components: {
Navigation
},
created(){
this.$store.dispatch( 'loadCafes' );
this.$store.dispatch( 'loadUser' );
}
}
</script>
编写好上述代码之后,布局组件就可以加载咖啡店列表及当前登录用户信息。
第三步:调整认证控制器重定向
这是添加布局到应用的最后一个步骤。
由于现在顶级链接指向布局页面,所以需要在用户登录成功后将重定向路由修改为 /home
,为此,打开 app/Http/Controllers/Web/AuthenticationController.php
文件,在 getSocialCallback()
方法中将重新向响应从
return redirect('/');
修改为
return redirect('/#/home');
至此,我们的页面布局已经创建完成,运行 npm run dev
重新构建应用,然后访问 http://roast.test
,登录成功后,会重定向到 http://roast.test/#/home
,此时页面显示如下:
可以看到导航组件已经显示出来了。
项目源码位于 Github 上:nonfu/roastapp。
49 Comments
没有出现导航,还是原来的app.blade. 哪里没有配好?
同楼上一样的错误,页面没有显示内容,空白的 app.js:47356 [Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <Anonymous> <Root>
尝试将 resources/assets/js/routes.js 中所有 Vue.component('xx', require('xxx')) 改为:Vue.component('xx', require('xxx').default)
app.js:11698 GET http://roast.test/api/v1/cafes 401 (Unauthorized) 这个怎么破
后端接口需要认证才能访问
看学院君github上的源码,把对应的user代码加上去,成功显示了用户的头像。但过程中发现modules/users.js中getters里面getUserLoadStatus方法返回的是一个函数,导致怎么都显示不了图片。最终我把它变成下面,直接返回state.userLoadStatus就正常了。不知是不是后面需要,还是怎么回事?
app.js:59496 [vuex] unknown action type: loadUser dispatch @ app.js:59496 boundDispatch @ app.js:59408 created @ app.js:56975 invokeWithErrorHandling @ app.js:43745 callHook @ app.js:46096 Vue._init @ app.js:46878 VueComponent @ app.js:47023 createComponentInstanceForVnode @ app.js:45172 init @ app.js:45003 merged @ app.js:45190 createComponent @ app.js:47849 createElm @ app.js:47796 createChildren @ app.js:47924 createElm @ app.js:47825 patch @ app.js:48385 Vue._update @ app.js:45822 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 (anonymous) @ app.js:12042 webpack_require @ app.js:20 (anonymous) @ app.js:11994 webpack_require @ app.js:20 (anonymous) @ app.js:63 (anonymous) @ app.js:66 app.js:42516 [Vue warn]: Error in render: "TypeError: Cannot read property 'avatar' of undefined"
found in
---> <Navigation> at resources/assets/js/components/global/Navigation.vue <Home> at resources/assets/js/pages/Layout.vue <Root> warn @ app.js:42516 logError @ app.js:43775 globalHandleError @ app.js:43770 handleError @ app.js:43730 Vue._render @ app.js:45429 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 init @ app.js:45007 createComponent @ app.js:47849 createElm @ app.js:47796 createChildren @ app.js:47924 createElm @ app.js:47825 patch @ app.js:48346 Vue._update @ app.js:45822 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 init @ app.js:45007 merged @ app.js:45190 createComponent @ app.js:47849 createElm @ app.js:47796 createChildren @ app.js:47924 createElm @ app.js:47825 patch @ app.js:48385 Vue._update @ app.js:45822 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 (anonymous) @ app.js:12042 webpack_require @ app.js:20 (anonymous) @ app.js:11994 webpack_require @ app.js:20 (anonymous) @ app.js:63 (anonymous) @ app.js:66 Show 14 more frames app.js:43779 TypeError: Cannot read property 'avatar' of undefined at Proxy.render (app.js:57215) at VueComponent.Vue._render (app.js:45427) at VueComponent.updateComponent (app.js:45943) at Watcher.get (app.js:46354) at new Watcher (app.js:46343) at mountComponent (app.js:45950) at VueComponent.Vue.$mount (app.js:50920) at VueComponent.Vue.$mount (app.js:53805) at init (app.js:45007) at createComponent (app.js:47849) logError @ app.js:43779 globalHandleError @ app.js:43770 handleError @ app.js:43730 Vue._render @ app.js:45429 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 init @ app.js:45007 createComponent @ app.js:47849 createElm @ app.js:47796 createChildren @ app.js:47924 createElm @ app.js:47825 patch @ app.js:48346 Vue._update @ app.js:45822 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 init @ app.js:45007 merged @ app.js:45190 createComponent @ app.js:47849 createElm @ app.js:47796 createChildren @ app.js:47924 createElm @ app.js:47825 patch @ app.js:48385 Vue._update @ app.js:45822 updateComponent @ app.js:45943 get @ app.js:46354 Watcher @ app.js:46343 mountComponent @ app.js:45950 Vue.$mount @ app.js:50920 Vue.$mount @ app.js:53805 (anonymous) @ app.js:12042 webpack_require @ app.js:20 (anonymous) @ app.js:11994 webpack_require @ app.js:20 (anonymous) @ app.js:63 (anonymous) @ app.js:66 Show 13 more frames app
两个问题,一个报500错误,一个视图渲染不出来,总觉得你的router-view这块儿写的不好,希望可以回头好好修改一下
虽然解决了,但是有点好奇,这个错的原因是什么?
没报错,视图就是渲染不出来