1:常用动态路由匹配parmas、query
实现:进入user页面,传入一个用户userid和用户type
parmas: (定义路由时) /user/:userid/type/:usetype,
使用改路由:
this.$router.push(
{
path:'/user/12/type/0',
}
)
获取: $route.parmas.userid,$route.parmas.usetype
query:(定义路由时)/user
使用该路由:
this.$router.push(
{
path:'/user',
query:{
userid:12,
usetype: 0
}
}
)
获取: $route.query.userid,$route.query.usetype
比较: 二者都可以实现传参功能,但是query更方便。
关注点:
(1)当使用路由参数时,例如从 /user/foo 导航到/user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。可以使用
// 监听
watch: {
'$route' (to, from) {
// 对路由变化作出响应...
}
}
// 路由守卫
beforeRouteUpdate(to, from, next) {
}
来响应路由参数的变化。
(2)使用parmas时,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高
2:路由嵌套:使用children配置,可以定义''默认子路由
const router = new VueRouter({
routes: [ { path: '/user/:id', component: User, children: [ // 当 /user/:id 匹配成功, // UserHome 会被渲染在 User 的 中 { path: '', component: UserHome },
// ...其他子路由
]
}
] })
3:路由导航的几种方式
//--------使用标签
<router-link :to="...">
//-------------使用router.push()方法,会向history栈中添加一条记录
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
//---------router.replace()方法和router.push()很像,区别是替换掉同名的记录
//---------router.go(n)n为负数代表后退,为正数代表前进,通常用来做返回上一页router.go(-1)
Vue Router 的导航方法 (push、 replace、 go) 在各类路由模式 (history、 hash 和 abstract) 下表现一致。
4:OA系统的侧边导航栏或者网站顶部的导航栏实现---命名视图
//举例web网站:
// 在app.vue文件中,定义三个组件共同构成一个完整的页面
<router-view class="top"></router-view>
<router-view class="main"></router-view>
<router-view class="footer"></router-view>
// top 用来展示固定的顶部导航
// main 网站不同页面的变化展示在这里
// footer 用来展示固定的底部网站信息
同时在router.js中配置
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: main,
a: top,
b: footer
}
}
]
})
// 可以理解为一个页面中有多个平级路由
5:页面只中提供一个窗口显示其他页面--嵌套命名视图
<!-- UserSettings.vue -->
<div>
<h1>User Settings</h1>
<NavBar/>
<router-view/>
<router-view name="helper"/>
</div>
在router.js中配置
const router = new VueRouter({
routes: [
{
path: '/settings',
// 你也可以在顶级路由就配置命名视图
component: UserSettings,
children: [
{
path: 'emails',
component: UserEmailsSubscriptions
}, {
path: 'profile',
components: {
default: UserProfile,
helper: UserProfilePreview
}
}]
}
]
// 可以理解为一个页面路由下,有多个子组件路由
6:路由的重定向redirect与别名alias
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' },
{ path: '/c', component: A, alias: '/d' }
]
})
/**
理解很简单:
重定向用户访问/a路由最终会跳到/b;
别名用户访问/d和访问/c是一样的,好比一个人既有中文名和英文名都是指同一个人
*/
6:路由模式
vue-router默认使用hash模式,带“#”,这种模式在地址栏里不好看,并且不会充分利用HTML5的history的api,推荐使用history模式
const router = new VueRouter({
mode: 'history',
routes: [...]
})
但是history模式需要服务器支持配置404页面,当用户输错路径时,这样就会自动跳转到默认的404界面,不会直接报错
7:路由守卫-可以用来做权限系统,鉴定用户是否有权限查看某个页面
全局守卫与路由独享守卫
在router.js中配置
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: main,
a: top,
b: footer
},
beforeEnter: (to, from, next) => {
// 路由独享守卫...
}
}
]
})
router.berforEach((to, from) => {
// ...
})
<!--2.5.0 新增-->
<!--在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,
区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。-->
router.afterEach((to, from) => {
// ...
})
组件内的守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
8:一些指令
v-model
一个vue的语法糖,可以用来实现双向绑定,自定义组件也可以使用
修饰符:
.lazy - 取代 input 监听 change 事件
.number - 输入字符串转为有效的数字
.trim - 输入首尾空格过滤
v-on
可以在2.4.0+版本上支持使用对象语法绑定多个事件
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
9:mvvm与mvc的区别
首先vue是mvvm模式的框架
angular是mvc,react是库,不是什么模式
mvvm与mvc的区别在于把组件业务逻辑处理的东西从c(controll)里面抽到vm里面,vm(viewmodel)。
vue是通过定义了一个观察者(observer观察者模式)watch()方法(基于监听Object.defineprototy(),set()与get()方法),再定义一个notifiy()方法通知变更,来实现单向数据流的双向绑定。
10:组件的全局注册与局部注册
全局注册:在main.js中使用Vue.component();
局部注册:
import {ComponentA, ComponentB} from '...'
new Vue({
el: ‘#app’,
components: {
‘component-a’: ComponentA,
‘component-b’: ComponentB
}
})
// 利用实例的components属性在页面组件中注册
全局注册的弊端:在项目启动时,可能还不需要某些组件,但就会注册这些暂时还不需要的组件。不利于性能优化
11:Vue实例
每一个拥有data函数,生命周期,methosd{}对象的vue页面都是一个实例。
获取父实例:vm.$parent
获取根实例:vm.$root
12:vue生命周期
页面初次加载会触发的周期: beforeCreate(), created(),beroreMount(),mounted(); data中的属性挂载完毕是在mounted()周期完成的。
created()和mounted()的区别:
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
通常会在created()周期内进行相关接口请求,在mounted()周期内根据需要刷新当前页面,比如移动端使用betterScrool时,通过利用this.$nextTick(()=>{})方法重新计算页面高度,触发滚动。
13:Vue.set(target,key,value)触发视图更新
在页面加载完成后,我们操作数组或对象不会触发视图更新,原因在于页面加载完成后,已挂载的值就不再是响应式的了,vue的视图更新只会对响应式的值起作用。
Vue.set()方法还是利用
defineReactive(ob.value, key, val)
ob.dep.notify()
把新增的值,重新变成响应式的,来触发视图更新
14: style标签scoped属性的使用,deep深度选择器
(1)scoped
<style scoped></style>
scoped属性可以使当前定义的样式只会影响当前组件和当前组件的子组件,不会影响当前组件的父组件。
(2)deep 当我们使用elm ui这种组件库时,有时为了改变组件库内某一元素的样式。
// 使用常规方法---无效
.el-table--enable-row-hover .el-table__body tr:hover>td {
background: lightblue !important;
color: #000;
}
// 必须使用deep---有效
.el-table--enable-row-hover /deep/ .el-table__body tr:hover>td {
background: lightblue;
color: #000;
}
15:v-if和v-for
v-for指令的优先级大于v-if.对同一个元素同时使用这两个指令,优先执行v-for.
还有语法规范上不能对同一个元素同时使用v-for和v-if,避免本该被隐藏的元素,被渲染出来。
16:为什么组件的data必须是一个函数。
// 创建一个组件
var Component= function() {
}
Component.prototype.data = {
a: 1,
b: 2
}
// 使用组件
var component1 = new Component()
var component2 = new Component()
component1.data.b = 3
component2.data.b // 3
当我们使用组件的时候,虽然data是在构造器的原型链上被创建的,但是实例化的component1和component2确是共享同样的data对象,当你修改一个属性的时候,data也会发生改变,这明显不是我们想要的效果。 所以
var Component= function() {
}
Component.prototype.data = function() {
return {
a: 1,
b: 2
}
}
// 使用组件
var component1 = new Component()
var component2 = new Component()
component1.data.b = 3
component2.data.b // 2
当data是一个函数时,每一个实例的data属性都是独立的,不会相互影响了。
这其实时js本身特性的原因,对象的每一个实例都指向对象对象,其中一个实例改变来对象的属性,也会影响到其它实例的获取结果。
17动态组件和异步组件
(1)动态组件
通过绑定is属性,来动态的切换该显示什么组件
<component v-bind:is="currentTabComponent"></component>
(2)异步组件
使用import和prmise封装一个方法,在需要加载该组件时(界面跳到该路由),才加载该组件。
// 全局注册时
Vue.component(
'async-webpack-example',
// 这个 `import` 函数会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
// 当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
18:Vue的两个核心
(1)数据驱动
通过使用Object.defineprototy()方法劫持目标的set()和get(),再配合watch()---观察者,dep依赖,notifity()方法,实现界面视图的更新
(2)组件系统
Vue的界面是有一个个组件堆起来的
19:Vue-router界面跳转和locations.href界面跳转的区别。
(1)首先Vue应用是单页面应用,所以Vue-router跳转不会刷新页面,locations.href会刷新页面
(2)Vue界面跳转基于底层的diff算法,实现了按需加载,减少了dom消耗。
20:router-link的坑
(1)在安卓手机上路由无效,
原因:babel 问题,框架底层。
解决:安装babel polypill插件解决
(2)router-link上绑定事件无效,
原因:router-link本身就是一个封装好的组件,不是html标签无法绑定事件,会阻止click事件
解决:使用.native修饰符,直接监听一个原生事件