Vue - 日常学习Two

413 阅读5分钟
XMind
XMind

1、对MVVM架构的理解?

  • Model层:表示数据模型。
  • View层:表示UI组件,用于视图展示。
  • ViewModel:监听数据模型的状态改变和控制视图的展示,VM通过双向数据绑定,将View层和Model层连接起来,所以当数据状态改变后视图会自动更新,无需人为干涉,因此使用MVVM可以令开发者更注重业务逻辑的开发,而不需要去手动操作DOM和关注数据状态的同步问题,复杂的数据状态维护交由MVVM统一管理。

2、对Vue生命周期的理解?

什么是生命周期?

一个组件从开始创建,初始化数据,编译模板,挂载DOM,渲染,等待更新,重新渲染,销毁等一系列过程,称之为生命周期。

Vue组件生命周期

  • beforeCreate(创建前):组件实例刚刚创建好,此时实例中还没有进行成员提升

  • created(创建后):组件实例已经提升成员,此时还没有进行页面渲染

  • beforeMount(挂载前):组件已编译好渲染模板,即将进行渲染

  • mounted(挂载后):组件已完成渲染,界面已经可见

  • beforeUpdate(更新前):组件实例中的数据是新的,但是界面还是旧的

  • updated(更新后):此时数据和界面都是最新的

  • beforeDestroy(销毁前):组件即将销毁

  • destroyed(销毁后):组件已经销毁

被keep-alive缓存的组件

  • activated(触发前):当被keep-alive缓存的组件激活时调用

  • deactivated(触发后): 当被keep-alive缓存的组件停用时调用

3、Vue异步请求适合在哪个生命周期中调用?

一般来说,Vue的异步请求可以在created和mounted中发送。如果在考虑效率问题的情况下,大部分时候会在created中进行请求。在mounted中发送请求会造成二次渲染。

  1. created生命周期的使用场景:一个页面的首次渲染来自于服务器端(SSR)

  2. created异步请求的优点:created支持SSR,能更快的获取服务端数据,减少页面Loading时间。

4、Vue组件之间如何通信?

父传子通信:

  1. props:一层一层传递下去
  2. $attrs:接收除了props声明外的所有绑定属性(class,style除外)
  3. $parent / $root:获取父/根作用域上下文
  4. provide / inject:导出注入方式,主要在开发高阶插件/组件库时使用。

子传父通信:

  1. $children:获取直接子组件的作用域上下文
  2. $refs:引用ref属性注册过的组件实例

组件事件通信:

  1. $emit:触发某个父作用域传递的事件(包括自定义事件)
  2. $listeners:获取父作用域传递的全部事件(包括自定义事件)
  3. event bus(事件总线):通过一个全局bus注册触发事件

全局共享数据通信

  1. Vuex:使用仓库来管理大量,复杂的组件间共享数据
// 代码演示:
// 1. props:一层一层传递数据
/*
<div id="app">
        <child_comp :title='title'></child_comp>
</div>
*/
var app = new Vue({
 el: '#app',
 data: {
  title: '传递给子组件的数据'
 },
 components: {
  // 子组件
  'child_comp': {
   props: ['title'], // 通过props绑定父作用域传递的数据
   template: '<li>{{ title }}</li>'
  }
 }
})
// 2. $attrs:接收除了props声明外的所有绑定属性(class,style除外)
/*
<div id="app">
        <child_comp :title='title'></child_comp>
</div>
*/
var app = new Vue({
 el: '#app',
 data: {
  title: '传递给子组件的数据'
 },
 components: {
  // 子组件
  'child_comp': {
   // 未被props声明的绑定属性会收纳进$attrs对象中
   template: '<li>{{ this.$attrs.title }}</li>'
  }
 }
})
// 3. $parent / $root:获取父/根作用域上下文
/*
<div id="app">
        <child_comp :title='title'></child_comp>
</div>
*/
var app = new Vue({
 el: '#app',
 data: {
  title: '传递给子组件的数据'
 },
 components: {
  // 子组件
  'child_comp': {
   // this.$parent得到父组件的上下文 / this.$root得到根组件的上下文
   template: `
    <li>{{ this.$parent.title }}</li>
    <li>{{ this.$root.title }}</li>
   `
  }
 }
})
// 4. provide / inject:导出注入方式,主要在开发高阶插件/组件库时使用。
/*
<div id="app">
        <child_comp :title='title'></child_comp>
</div>
*/
var app = new Vue({
 el: '#app',
 // 使用provide方式创建数据对象并导出
 provide: {
  title: '传递给子组件的数据'
 },
 components: {
  // 子组件
  'child_comp': {
   // 需要用到导出数据的组件使用inject注入
   inject: ['title'],
   template: '<li>{{ title }}</li>'
  }
 }
})
// 5. $children:获取直接子组件的作用域上下文
/*
<div id="app">
        <child_comp :title='title'></child_comp>
</div>
*/
var app = new Vue({
 el: '#app',
 data: {
  title: ''
 },
 components: {
  // 子组件
  'child_comp': {
   data(){
    return {
     title: '传递给父组件的数据'
    }
   },
   template: '<li></li>'
  }
 },
 mounted(){
  // 获取直接子组件的上下文
  this.title = this.$children[0].title
 }
})
// 6. $refs:引用ref属性注册过的组件实例
/*
<div id="app">
  // 通过ref注册引用
        <child_comp ref=‘dom’></child_comp>
</div>
*/
var app = new Vue({
 el'#app',
 data: {
  title''
 },
 components: {
  // 子组件
  'child_comp': {
   data(){
    return {
     title'传递给父组件的数据'
    }
   },
   template'<li></li>'
  }
 },
 mounted(){
  // 通过$refs获取dom对应的组件实例
  this.title = this.$refs.dom.title
 }
})
// 7. $emit:触发某个父作用域传递的事件(包括自定义事件)
//    $listeners:获取父作用域传递的全部事件(包括自定义事件)
/*
<div id="app">
        <child_comp @click='handleClick' @test='fun'></child_comp>
</div>
*/
var app = new Vue({
 el'#app',
 data: {
  title''
 },
 methods: {
  handleClick(param){
   this.title = param;
  }
 },
 components: {
  // 子组件
  'child_comp': {
   data(){
    return {
     title'传递给父组件的数据'
    }
   },
   template'<li @click="callback">点击触发事件</li>',
   methods: {
    callback(){
     // 触发click事件
     this.$emit('click'this.title);
     // 得到所有事件对象
     console.log(this.$listeners); // {click: fun(), test: fun()};
    }
   }
  }
 }
})

5、computed和watch有什么区别?

computed(计算属性): 计算属性中的成员会提升到vue实例中,因此,在模板中可以直接当作属性使用,使用时,实际调用的是对于的方法。

  1. 计算属性在使用时会计算属性的依赖,当依赖没有发生变化时,vue会直接使用之前缓存的结果。
  2. 计算属性可以配置get和set两个方法,分别用于读取和设置。

watch(侦听属性): 侦听属性用来观察和响应vue实例上的数据变动。


由于计算属性会缓存结果,对于一个性能开销较大的计算,如果多个地方同时使用同一个计算属性,只需要计算一次,如果使用侦听属性,每调用一次都会重新计算一次。

6、Vue是如何实现双向数据绑定的?

Vue2.x:使用Object.defineProperty实现数据双向绑定。

Vue3.x:使用ES6中的Proxy进行代理。


Object.defineProperty的缺陷:

  1. 无法检测数组下标的变化。
    Vue中使用数组方法可以监听到是因为Vue对这些方法进行了重写。
  2. 只可以监听属性,无法监听对象本身。
    Vue是通过遍历对象的每个属性,通过添加getter/setter属性修改成访问器属性。而不是监听对象本身,所以对于后来给对象添加的属性难以监听。
  3. 当对象增删的事件,监听不到变化。
    原因同上。Vue监听的是对象属性,而不是对象本身。

本文使用 mdnice 排版