Vue2.0笔记

246 阅读4分钟

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修饰符,直接监听一个原生事件