Vue知识点汇总

一、MVVM的理解

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定。

  1. Model 代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
  2. View 代表UI 组件,它负责将数据模型转化成UI 展现出来。
  3. ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。

二、MVC和MVVM的区别

1、什么是MVC

MVC 即 Model-View-Controller 的缩写,就是 模型—视图—控制器,也就是说一个标准的Web 应用程式是由这三部分组成的:

1)、View :代表UI,展示数据

2)、Model :代表数据模型,管理数据

3)、Controller :处理来自用户的请求,并将 Model 返回给用户

2、MVC的缺点:

1)、开发者在代码中大量调用相同DOM API,处理繁琐 ,操作冗余,使得代码难以维护。

2)、大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

3)、 当 Model 频繁发生变化,开发者需要主动更新到View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到Model 中,这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。

3、MVVM可以解决这几个问题

1)、无需直接操作DOM API,使用相关的指令、对数据进行维护即可。

2)、无需大量操作dom,因为它会模拟真实 DOM 树,通过算法计算,找出差异,局部更新到真实的dom树中,节省大量的dom操作。

3)、ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

三、Vue.js是什么?

Vue.js是一款流行的MVVM前端框架,旨在更好地组织与简化Web开发。

Vue官方:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

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

用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。

js实现简单的双向绑定:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    输入:<input type='text' id='inputText'/><br>
    动态值:<span id="show"></span>
</body>
<script>
    var inputText = document.getElementById("inputText");
    var show = document.getElementById("show");
    //输入框添加 input事件
    inputText.addEventListener("input",function(e){
        //给劫持对象设置为输入后的值
        defineObj.value = e.target.value;
    })
    //劫持对象
    var defineObj = {};
    //defineProperty进行劫持
    Object.defineProperty(defineObj, 'value', {
    configurable: true,
    enumerable: true,
    get:function() {
        return val;
    },
    set: function(newVal){
        val = newVal;
        //设置输入值跟随变化
        inputText.value = val;
        //设置显示值跟随变化
        show.innerHTML = val;
        
    }
    })

</script>
</html>

五、响应式原理

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty  ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把接触过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

注意点:

1)、对象

Vue 会在初始化实例时对 属性 执行 getter/setter 转化,所以属性必须在data上存在才能响应,如:

var vm = new Vue({
  data:{
    a:1
  }
})

vm.a是响应的,比如vm.a=2,会触发视图的更新;

但vm.b=2这就不是响应的,因为b本身在data中是不存在的,没有被添加setter/getter,不会响应。

若要响应,可以用 Vue.set(object, propertyName, value) 方式,比如:

<body>
    <div id='app'>
        <p>{{a}}</p>   
        <p>{{testObj}}</p>     
    </div>
</body>
<script src="./dist/vue.js"></script>
<script>
var vm = new Vue({
    el:'#app',
    data:{
        a:1,
        testObj:{}
    }
})

Vue.set(vm.testObj, 'b', 2)

</script>
</html>

也可以用 $set 方式,把上述代码的Vue.set...改成  vm.$set(vm.testObj, 'b', 2) 既可。

1)、数组

Vue 不能检测以下数组的变动:

  1. 当你利用索引直接设置一个数组项时,例如:vm.arr[1] = 2;
  2. 当你修改数组的长度时,例如:vm.arr.length = 1

可以这样使用:

Vue.set(vm.arr, 1, 6),设置第2个元素为6,Vue.set(vm.arr, 2, 7),设置第3个元素为7。

splice方法,vm.arr.splice(2,1,8) 将第3个元素替换为8

vm.$set(vm.arr, 2, 9) 将第3个元素更新为9.

六、Vue的生命周期

1、什么是vue生命周期?

答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。

2、vue生命周期的作用是什么?

答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

3、vue生命周期总共有几个阶段?

答:它可以总共分为8个阶段:创建前/后、载入前/后、更新前/后、销毁前/销毁后。

4、第一次页面加载会触发哪几个钩子?

答:会触发下面这几个beforeCreate、created、beforeMount、mounted 。

5、DOM 渲染在哪个周期中就已经完成?

答:DOM 渲染在 mounted 中就已经完成了。

beforeCreate(创建前),在数据观测和初始化事件还未开始

created(创建后),完成数据观测,属性和方法的运算,初始化事件, $el 属性还没有显示出来

beforeMount(载入前),在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。

mounted(载入后),在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。

beforeUpdate(更新前),在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。

updated(更新后),在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。

beforeDestroy(销毁前),在实例销毁之前调用。实例仍然完全可用。

destroyed(销毁后),在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

七、模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

语法说明
插值 {{}}显示普通文本 
v-text显示普通文本 
v-html输出真正的 HTML
v-once能执行一次性地插值,当数据改变时,插值处的内容不会更新
v-if、v-else-if条件判断,当得到结果为true时,所在的元素才会被渲染。
v-else

v-else是和v-if相连使用的

v-else元素必须紧跟在带 v-if或者v-else-if的元素的后面,否则它将不会被识别。

v-show

当得到结果为true时,所在的元素才会显示;

如果为false则不显示,但是元素已经渲染,style.display='none';

true/false的切换就是对元素的 CSS 属性display的切换。

v-for遍历数据渲染页面是非常常用的需求,Vue中通过v-for指令来实现
v-modelv-model在表单控件元素上创建双向数据绑定
v-bind 它的作用是在属性上使用vue数据
v-on 简写为 @

v-on指令用于给页面元素绑定事件。

如 click:v-on:click 

八、Vue中文本渲染三种方法 {{}}、v-html、v-text的区别

v-text和{{}}

说明:显示普通文本

简写方式:{{}}

语法:

<p v-text="msg"></p>
<p>{{msg}}</p>

实例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
 
    <body>
        <div id="app">
       	   <p v-text='msg1'></p>
       	   <p>{{msg2}}</p>
        </div>
    </body>
    <script src="../vue.js"></script>
    <script>
       var vm = new Vue({
            el: '#app',
            data: {
              msg1:'这是一个消息',
              msg2:'这是另外一个消息'
            }
        })
    </script>
</html>

页面效果:

v-html

说明:输出真正的 HTML

语法:<p v-html='msg'></p>

实例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
 
    <body>
        <div id="app">
       	   <p v-html='msg3'></p>
        </div>
    </body>
    <script src="../vue.js"></script>
    <script>
       var vm = new Vue({
            el: '#app',
            data: {
              msg1:'这是一个消息',
              msg2:'这是另外一个消息',
              msg3:'<strong>这是一个html<strong>'
            }
        })
    </script>
</html>

页面效果:

区别

v-html输出真正的 HTML,v-text仅渲染标签,不能解析 HTML 代码

实例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
 
    <body>
        <div id="app">
       	   <p v-text='msg3'></p>
       	   <p>{{msg3}}</p>
       	   <p v-html='msg3'></p>
        </div>
    </body>
    <script src="../vue.js"></script>
    <script>
       var vm = new Vue({
            el: '#app',
            data: {
              msg1:'这是一个消息',
              msg2:'这是另外一个消息',
              msg3:'<strong>这是一个html<strong>'
            }
        })
    </script>
</html>

页面效果:

总结:

v-text和{{}}表达式渲染数据,不解析标签,如果有标签则直接当做字符输出到页面上。

v-html不仅可以渲染数据,而且可以解析标签。

 

九、Vue中Computed和Watch的用法及其区别

计算属性(computed)

我们都知道vue在模板中使用表达式非常便利,比如{{message}};其实vue是支持更复杂的逻辑的,比如{{message+message1+message2}},但vue建议我们使用一个表达式。如果需要多于一个表达式的逻辑,应当使用计算属性。

示例

如:a=1,b=2,c=3,计算a+b+c并展示到页面上

写法1(多表达式):

 <div id="example">
      <p>{{a+b+c}}</p>
 </div>
<script>
var vm = new Vue({
  el: '#example',
  data: {
    a: 1,
    b:2,
    c:3
  }
})
</script>

写法2(计算属性):

<div id="example">
    <p>{{d}}</p>
</div>
<script>
var vm = new Vue({
  el: '#example',
  data: {
    a: 1,
    b:2,
    c:3
  },
  computed: {
    d: function () {
      return this.a + this.b+ this.c
    }
  }
})
 
</script>

比较一下

1.这两种写法都能够得到我们想要的结果;

2.第一种多表达式的写法毫无疑问会监控a、b、c这3个属性,跟随属性而变化,第二种计算属性d也是依赖于a、b、c,当这3个属性发生变化,d也会跟着更新。

3.这里仅仅是a+b+c这里简单的逻辑,所以看不出这两种有多大区别,一旦过多的逻辑运算会让模板变得复杂且难以维护,而且这种转化无法复用;用计算属性的话逻辑简单清晰好维护且易复用

当然method也能实现,对,你肯定也想到了

下面的实例是将计算属性和方法的使用放到一起来做比较

  <div id="example">
        <p>计算属性第1次:{{d}}</p>
        <p>计算属性第2次:{{d}}</p>
        <p>计算属性第3次:{{d}}</p>
        <p>计算属性第4次:{{d}}</p>
        <p>方法调用第1次:{{modthod_d()}}</p>
        <p>方法调用第2次:{{modthod_d()}}</p>
        <p>方法调用第3次:{{modthod_d()}}</p>
        <p>方法调用第4次:{{modthod_d()}}</p>
    </div>
<script>
var vm = new Vue({
  el: '#example',
  data: { 
    a:1,
    b:2,
    c:3
  },
  methods:{
    modthod_d:function(){
        console.log('method_d')
        return this.a + this.b+ this.c
    }
  },
  computed: {
    d: function () {
        console.log('computed_d')
      return this.a + this.b+ this.c
    }
  }
})
 
</script>

运行到浏览器中,看输出

对比一下

  1. 都能正确的调用,并且如果我们改变其中的依赖就会产生更新;
  2. 使用method:使用几次就执行相应的函数几次,所以method_d被打印了4次;
  3. 使用计算属性:因为有缓存,如果依赖的数据未发生变化,多次访问则函数只执行一次,所以computed_d仅仅打印了一次,因为第一次计算后就有缓存了,后续无需再计算了;
  4. 计算属性因为有缓存的存在,所以可以节省一些资源,性能肯定就有所提高了,故更建议使用计算属性。

计算属性的setter getter

一般情况下,我们只是使用了计算属性中的gettter属性(如上面的几个例子),但它是支持setter属性的,如下:

 <div id="example">
        <p>计算属性:{{d}}</p>
        <button @click="incre">set计算属性</button>
    </div>
 
<script>
var vm = new Vue({
  el: '#example',
  data: { 
    a:1,
    b:2,
    c:3,
    n:1
  },
  methods:{
    incre:function(){
        this.d=++this.n;
    }
  },
  computed: {
    d:{
       get:function () {
         console.log('computed_d')
         return this.a + this.b+ this.c
        },
        set:function(newVal){
            this.a=newVal;
        }
 
    } 
  }
})

页面效果

如上实例中的,我们给计算属性d写了set,就可以通过this.d的方式来进行想要的操作了。

监听属性(watch)

单个属性实例

<div id="example">
        <p>{{a}}</p>
        <button @click="mod_a">修改a</button>
    </div>
<script>
var vm = new Vue({
  el: '#example',
  data: { 
    a:1
  },
  methods:{
    mod_a:function(){
        this.a++;
    }
  },
  watch:{
    a:function(newVal,oldVal){
      console.log("新值:"+newVal+" 旧值:"+oldVal);
    }
  }
})
 
</script>

页面效果

对象监控实例(一个一个的属性监控)

  <div id="example">
        <p>{{person}}</p>
        <input v-model="person.name">
    </div>
 
<script>
var vm = new Vue({
  el: '#example',
  data: { 
    a:1,
    person:{
      name:'张三',
      age:30
    }
  },
  methods:{
    mod_a:function(){
        this.a++;
    }
  },
  watch:{
    'person.name':function(newVal,oldVal){
      console.log("新值:"+newVal+" 旧值:"+oldVal);
    }
  }
})
 
</script>

测试一下:

深度监控对象(就是不用每个属性都单独写监控,一次监控此对象的所有属性)

 <div id="example">
        <p>{{person}}</p>
        name:<input v-model="person.name"><br>
        age:<input v-model="person.age">
    </div>
 
<script>
var vm = new Vue({
  el: '#example',
  data: { 
    a:1,
    person:{
      name:'张三',
      age:30
    }
  },
  methods:{
    mod_a:function(){
        this.a++;
    }
  },
  watch:{
    person:{
       handler(newVal,oldVal) {
         console.log("新值:"+JSON.stringify(newVal)+" 旧值:"+JSON.stringify(oldVal));
      },
      deep: true
    }
  }
})
 
</script>

页面效果:

计算属性 和属性监听的区别:

1.计算属性变量在computed中定义,属性监听在data中定义。

2.计算属性是声明式的描述一个值依赖了其他值,依赖的值改变后重新计算结果更新DOM。属性监听的是定义的变量,当定义的值发生变化时,执行相对应的函数。

这两者选择和使用没有对错之分,只是希望能更好的使用,而不是滥用,我个人更喜欢用计算属性。

十、事件修饰符

表示说明用法
.stop

 

阻止事件冒泡<a href="www.baidu.com" @click.stop="doThis"></a>
.prevent 阻止事件的默认行为<a href="www.baidu.com" @click.prevent="doThis"></a>
.capture捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。<div @click.capture="doThis">DIV</div>
.self将事件绑定到自身,只有自身才能触,通常用于避免冒泡事件的影响<div @click.self="doThis">DIV</div>
.once设置事件只能触发一次,比如按钮的点击等。<button @click.once="doThis"></button>

.passive

 passive这个修饰符会执行默认方法;

通俗的说就是不用“阻止默认动作”

<a href="www.baidu.com" @click.passive="doThis"></a>

使用修饰符时,可以根据实际需求结合使用,但顺序很重要;相应的代码会以同样的顺序产生。

十一、自定义指令

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

update:所在组件的 VNode 更新时调用,但是可能发生在其子VNode 更新之前。指令的值可能发生了改变,也可能没有。但是通过比较更新前后的值来忽略不必要的模板更新

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

钩子函数的参数有el、binding、vnode 和 oldVnode

十二、组件通讯

父子组件的通信

父组件传给子组件:子组件通过props方法接受数据;

子组件传给父组件: $emit 方法传递参数

非父子组件的eventBus通信

eventBus这种通信方式,针对的是非父子组件之间的通信,它的原理还是通过事件的触发和监听。

但是因为是非父子组件的关系,他们需要有一个中间组件来连接,eventBus就相当于中转站。

利用本地缓存实现组件通信

通过window.localStorage.getItem(key) 获取数据

通过window.localStorage.setItem(key,value) 

存储数据用JSON.parse() 、JSON.stringify() 做格式转换。

Vuex通信

比较复杂

十三、Vue路由的钩子函数

 beforeEach主要有3个参数to,from,next。

 to:route即将进入的目标路由对象。

 from:route当前导航正要离开的路由。

 next:function一定要调用该方法resolve这个钩子,执行效果依赖next方法的调用参数。可以控制网页的跳转。

十四、nextTick

由于Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保得到更新后的DOM,所以设置了 Vue.nextTick()方法。

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

//改变数据
vm.message = 'changed value'

//想要立即使用更新后的DOM。但是DOM还没有立即更新
console.log(vm.$el.textContent) // 并不会得到'changed value'

//nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
    // DOM 更新了
    console.log(vm.$el.textContent)    //可以得到'changed value'
})

 

就先整理了这些,欢迎大家点赞 + 关注 + 收藏,收工咯!

关注下方公众号,有更多资料实例代码面试技巧奉上!

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程界小明哥

请博主喝瓶水,博主持续输出!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值