小技巧1:webstorm中reformat可以自动将分号加入,如果没有的话请在seetings-editor-code style中设置
小技巧2:webstorm中可以设置组建模板,进入settings-file and code templates
初步导航栏
//index.ts
import Vue from 'vue';
import VueRouter from 'vue-router';
import Money from '@/views/Money.vue';
import Labels from '@/views/Labels.vue';
import Statistics from '@/views/Statistics.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',//默认路径
redirect: '/money'
},
{
path: '/money',
component: Money
},
{
path: '/labels',
component: Labels
},
{
path: '/statistics',
component: Statistics
}
];
const router = new VueRouter({
routes
});
export default router;
在App.vue中使用 <router-view/> 进行页面渲染,使用 <router-link> 进行页面切换
<template>
<div>
<router-view/>
<hr/>
<div>
<router-link to="/money">记账</router-link>
|
<router-link to="/labels">标签</router-link>
|
<router-link to="/statistics">统计</router-link>
</div>
</div>
</template>
<router-view>
<router-view> 组件是一个 functional 组件,渲染路径匹配到的视图组件。<router-view> 渲染的组件还可以内嵌自己的 <router-view>,根据嵌套路径,渲染嵌套组件。
其他属性 (非 router-view 使用的属性) 都直接传给渲染的组件, 很多时候,每个路由的数据都是包含在路由参数中。
<router-link>
<router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。
<router-link> 比起写死的 <a href="..."> 会好一些,理由如下:
- 无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。
- 在 HTML5 history 模式下,
router-link会守卫点击事件,让浏览器不再重新加载页面。 - 当你在 HTML5 history 模式下使用
base选项之后,所有的to属性都不需要写 (基路径) 了。
添加404页面
//index.ts
{
path: '*',//*表示匹配其他所有路径
component: NotFound
}
//NotFound.vue
<template>
<div>
<div>当前页面不存在,请检查网址是否存在</div>
<div>
<router-link to="/">返回首页</router-link>
<!-- 第二种写法<a href="#/">返回首页</a>-->
</div>
</div>
</template>
添加导航栏样式
忠告:千万不要在手机上使用fixed定位,本项目使用flex
Layout组件
使用插槽传递内容:
//Layout.vue
<template>
<div class="nav-wrapper">
<div class="content">
<slot/>
<!-- 插槽:放置用户传进来的内容-->
</div>
<Nav/>
</div>
</template>
<script lang="ts">
export default {
name: 'Layout'
};
</script>
<style lang="scss" scoped>
.nav-wrapper {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
overflow: auto;//超出后自动滚动
flex-grow: 1; //尽量把所有高度都给content
}
</style>
在Money.vue(以及Labels.vue和Statistics.vue)中使用Layout
<template>
<div>
<Layout>
Money.vue
<!-- 向插槽传的内容-->
</Layout>
</div>
</template>
<script lang="ts">
export default {
name: 'Money'
};
</script>
插槽
Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。
它允许你像这样合成组件:
<navigation-link url="/profile">
Your Profile
</navigation-link>
然后你在 <navigation-link> 的模板中可能会写为:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML:
<navigation-link url="/profile">
<!-- 添加一个 Font Awesome 图标 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>
甚至其它的组件:
<navigation-link url="/profile">
<!-- 添加一个图标的组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
如果 <navigation-link> 的 template 中没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。
引入SVG
先去阿里巴巴矢量图标库下载需要的icons
svg-sprite-loader -D
安装loader
yarn add svg-sprite-loader -D
注意vue组建里面没有webpack.config.js,所以需要把webpack的配置改到vue.config.js
const path = require('path')
module.exports = {
lintOnSave: false,
chainWebpack: config =>{
const dir = path.resolve(__dirname, 'src/assets/icons')
config.module
.rule('svg-sprite')
.test(/.svg$/)
.include.add(dir).end() // 包含 icons 目录
.use('svg-sprite-loader-mod').loader('svg-sprite-loader-mod').options({extract:false}).end()
.use('svgo-loader').loader('svgo-loader')
.tap(options => ({...options, plugins: [{removeAttrs: {attrs: 'fill'}}]})).end()
config.plugin('svg-sprite').use(require('svg-sprite-loader/plugin'), [{plainSprite: true}])
config.module.rule('svg').exclude.add(dir) // 其他 svg loader 排除 icons 目录
// config.module
// .rule('svg-sprite')
// .test(/.(svg)(?.*)?$/)
// .include.add(dir).end()
// .use('svg-sprite-loader-mod').loader('svg-sprite-loader-mod').options({extract: false}).end()
// .use('svgo-loader').loader('svgo-loader')
// .tap(options => ({...options, plugins: [{removeAttrs: {attrs: 'fill'}}]}))
// .end()
// config.plugin('svg-sprite').use(require('svg-sprite-loader-mod/plugin'), [{plainSprite: true}])
// config.module.rule('svg').exclude.add(dir)
}
}
注意:
.use('svgo-loader').loader('svgo-loader') .tap(options => ({...options, plugins: [{removeAttrs: {attrs: 'fill'}}]})).end()这段代码会把icons本来的颜色覆盖掉从而可以在后续点击时对整个icon进行高亮。如果icon本身带颜色,可以选择去掉这两行代码。
使用active-class进行高亮选择
<template>
<nav>
<router-link to="/labels" class="item" active-class="selected">
<Icon name="label"/>
标签
</router-link>
<router-link to="/money" class="item" active-class="selected">
<Icon name="money"/>
记账
</router-link>
<router-link to="/statistics" class="item" active-class="selected">
<Icon name="statistics"/>
统计
</router-link>
</nav>
</template>
...
<style lang="scss" scoped>
@import "~@/assets/style/helper.scss";
nav {
...
> .item.selected{
color: $color-highlight;
}
}
</style>
active-class会在对象被点击后加入selected标签,从而后续通过 > .item.selected 调整颜色。