Vue 基础扫盲

May 08, 2019 10:48·2.4k words ·9 minutes read

对 mvvm 模式的理解

mvvm 是 model view viewModel 的缩写

model 是数据模型 定义数据修改和操作的业务逻辑

view 是 ui 组件 将数据模型转换成 ui 展现出来

viewModel 监听模型数据的改变; 控制视图行为; 处理用户交互;

通过双向数据绑定将view和model连接起来 view和model之间的同步是自动的 无需人为干涉

Vue 生命周期

vue 实例从创建到销毁的过程,就是生命周期:
create, mount, update, destroy

beforeCreate

组件实例被创建之前,获取不到 `props` 或者 `data` 中的数据

created

组件实例刚刚被创建,获取不到props或者data中的数据

beforeMount

挂载开始之前被调用

mounted

dom 节点被渲染到文档内,一些需要 dom 的操作在此时才能正常进行

beforeUpdate

数据更新时调用,发生在虚拟 dom 重新渲染之前 
在这个钩子中进一步地更改状态 不会触发附加的重渲染过程

updated

组件DOM已经更新,可以执行依赖于DOM的操作,但应该避免在此期间更改状态 有可能会导致更新无限循环

beforeDestroy

实例销毁之前调用,实例仍然可以调用

destroyed

实例被销毁后调用 调用后vue实例指示的所有东西都会解绑,事件监听器会被移除,所有子实例也会被销毁,该钩子在服务器端渲染期间不被调用

Vue 实现双向数据绑定的原理

数据劫持 + 发布订阅者模式
劫持 `object.defineProperty()` 中的 `set` 和 `get` 属性

Vue 组件间如何传递参数

父组件给子组件:父组件通过子标签绑定的属性,子组件通过 props 接收
子组件给父组件:子组件通过 $emit 函数将值发送给父组件
  • 每个Vue实例都实现了事件接口:使用 $on(evntName) 监听事件;使用 $emit(eventName,optionalPayload) 触发事件。

      因此,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件
    

e.g

父组件在组件上定义了一个自定义事件 childFn,事件名为 parentFn 用于接受子组件传过来的 message

<!-- 父组件 -->
<template>
    <div class="test">
      <test-com @childFn="parentFn"></test-com>
      <br/> 
      子组件传来的值 : {{message}}
    </div>
</template>

<script>
export default {
    // ...
    data: {
        message: ''
    },
    methods: {
        parentFn(payload) {
            this.message = payload;
        }
    }
}
</script>

子组件是一个 buttton 按钮,并为其添加了一个 click 事件,当点击的时候使用 $emit() 触发事件,把 message 传给父组件。

<!-- 子组件 -->
<template> 
    <div class="testCom">
        <input type="text" v-model="message" />
        <button @click="click">Send</button>
    </div>
</template>
<script>
export default {
    // ...
    data() {
        return {
          // 默认
          message: '我是来自子组件的消息'
        }
    },
    methods: {
        click() {
            this.$emit('childFn', this.message);
        }
    }    
}
</script>

通过 "props down , events up" 我们就简单的实现了父子组件之间的双向传值

React 和 Vue 的区别

共性:

都支持服务端渲染,组件化开发通过 props 参数进行父子组件数据的传递,数据驱动视图

区别:

vue 是双向数据绑定,react 数据流动是单向的

Vue渲染过程是跟踪每一个组件的依赖,更改了哪个组件渲染哪个,react重新渲染全部组件

keey-alive 的了解

1. 是Vue的内置组件,可以使被包含的组件保留状态,避免重新渲染

2. 拥有两个独有的生命周期钩子函数,activated 和 deactivated

3. 被包裹在keep-alive中的组件的状态将会被保留
    例如:我们将某个列表类组件内容滑动到第100条位置,那么我们在切换到一个组件后再次切换回到该组件,该组件的位置状态依旧会保持在第100条列表处

routerouter 的区别

route

路由信息对象,包括 path, params, query, name 等路由信息参数

router

路由实例对象,包括了路由的跳转方法,钩子函数等

queryparams 的区别

query 相当于 get 请求,页面跳转的时候可以在地址栏看到请求参数,用 path 来引入;params 相当于 post,地址栏不显示参数,用 name 来引入

Vue 常用的修饰符

.prevent 阻止元素默认跳转

.stop 阻止单击事件冒泡

.capture 捕获

.once 只执行一次

怎么定义 vue-router 的动态路由以及如何获取传过来的动态参数

定义 vue-router 的动态路由

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

获取传过来的动态参数

<div>User {{ $route.params.id }}</div>

vue + axios 登录拦截

我们一般用 beforeEach 这个全局前置守卫来做路由跳转前的登录验证。
const router = new VueRouter({
  routes: [
    {
      path: '/login',
      name: 'login',
      meta: { name: '登录' },
      component: () => import('./views/login.vue')
    },
    {
      path: '/welcome',
      name: 'welcome',
      meta: { name: '欢迎', auth: true },
      component: () => import('./views/welcome.vue')
    }
  ]
})

在上面的 routers 中我们配置了 2 个路由,login 和 welcome,welcome 需要登录认证,我们在 welcome 路由的 meta 中加入了 auth: true 作为需要认证的标识。

beforeEach 全局前置守卫的配置:

router.beforeEach((to, from, next) => {
  if (to.meta.auth) {
    if (getToken()) {
      next()
    } else {
      next('/login')
    }
  } else {
    next()
  }
})
要想统一处理所有http请求和响应,就得用上 axios 的拦截器。通过配置 http response inteceptor,当后端接口返回 401 Unauthorized(未授权),让用户重新登录。
// http request 拦截器
axios.interceptors.request.use(
    config => {
        if (store.state.token) {  // 判断是否存在token,如果存在的话,则每个http header都加上token
            config.headers.Authorization = `token ${store.state.token}`;
        }
        return config;
    },
    err => {
        return Promise.reject(err);
    });

// http response 拦截器
axios.interceptors.response.use(
    response => {
        return response;
    },
    error => {
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    // 返回 401 清除token信息并跳转到登录页面
                    store.commit(types.LOGOUT);
                    router.replace({
                        path: 'login',
                        query: {redirect: router.currentRoute.fullPath}
                    })
            }
        }
        return Promise.reject(error.response.data)   // 返回接口返回的错误信息
    }
);

Vuex 是什么?怎么使用?哪种功能场景使用它?

// todo

Vuex

Vue 路由实现原理

只有2种实现方式 hash 模式和 history 模式

hash 模式

带 # 号的,当 # 后面的哈希值发生变化时,可以通过 hashchange 事件来监听到 URL 变化,进行页面跳转(简单,兼容性好)

history 模式

h5 新功能,使用 history.pushState 和 history.replaceState 改变 URL
const router = new VueRouter({
    mode: 'history',
    routes: [...]
})
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

Vue Router | 后端配置例子

computedwatch 区别

computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容

watch 监听到值的变化就会执行回调,在回调中进行一些逻辑操作

一般需要依赖别的属性来动态获得值的时候可以使用 computed

对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用 watch

侦听器(watch)解释:

watch: {
    // 属性名 --> 侦听对象
    // 函数参数 --> 侦听对象的变化值
    firstName: function (val) {
        // 函数体 --> 侦听后的操作
        this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
        this.fullName = this.firstName + ' ' + val
    }
}

v-ifv-show 的区别

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。