vue相关知识点整理

本文详细介绍了Vue的核心概念,包括MVVM、双向数据绑定、系统指令、生命周期钩子函数、组件传值及Vuex的使用。重点探讨了响应式原理,通过Object.defineProperty()实现数据劫持,以及Vue的模板引擎和渲染过程。此外,还涵盖了Vue指令如v-if/v-for、事件修饰符以及组件优化策略,旨在全面解析Vue的运作机制及其在实际开发中的应用。
摘要由CSDN通过智能技术生成

Vue

vue的特点

  1. 简单易学:国⼈开发,中⽂⽂档,不存在语⾔障碍 ,易于理解和学习;
  2. 灵活:它可以与已知第三方工具(vuex),第三方Ui库(elementUi)(vant),结合使用
  3. 高效:虚拟dom,diff算法,大大的提升了页面的运行效率
  4. 轻量级框架:只关注视图层,是⼀个构建数据的视图集合,⼤⼩只有⼏⼗kb
  5. 双向数据绑定:在数据操作方面更为简单
  6. 组件化:实现了html的封装和重⽤,在构建单⻚⾯应⽤⽅⾯有着独特的优势;
  7. 视图,数据,结构分离:使数据的更改更为简单,不需要进⾏逻辑代码的修改,只需要操作数据就能完成相关操作;

vue的核心概念

数据驱动:ViewModel,保证数据和视图的一致性
组件系统:应用类UI可以看作全部是由组件树构成的

MVVM / Vue的三要素
响应式:vue 如何监听到 data 的每个属性变化?

模板引擎:vue 的模板如何被解析,指令如何处理?

渲染:vue 的模板如何被渲染成 html ?以及渲染过程

MVVM

单向绑定:把Model绑定到View,用JavaScript代码更新Model时,View就会自动更新。不需要进行额外的DOM操作,只需要进行Model的操作就可以实现视图的联动更新。

双向绑定:把Model绑定到View的同时也将View绑定到Model上,这样就既可以通过更新Model来实现View的自动更新,也可以通过更新View来实现Model数据的更新。

MVVM:分离由js对象表示的model模型层和view视图层,两者之间通过viewmodel交互,Model 和 ViewModel 之间的交互是双向的,通过数据来驱动视图,只需要关心数据变化,DOM操作被封装。因此View的变化会同步到Model中,而Model的变化也会立即反应到View 上。

MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。其中 View 负责页面的显示逻辑,Model 负责存储页面的业务数据,以及对相应数据的操作。并且 View 和 Model 应用了观察者模式,当 Model 层发生改变的时候它会通知有关 View 层更新页面。Controller层是 View 层和 Model 层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Controller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对 Model 的修改,然后 Model 层再去通知 View 层更新。

响应式原理

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时发布消息给订阅者,触发相应的监听回调,当属性被访问或改变时通知变化,而产生更新数据和视图。

data属性定义了getter、setter对属性进行劫持,当属性值改变就会notify通知watch对象,而watch对象则会重新触发组件呈现功能,继而更新view上的DOM节点树。
反之,view上输入数据时,也会触发data变更,也会触发订阅者watch更新,这样子model数据就可以实时更新view上的数据变化。这样一个过程就是vue的数据双向绑定了

双向绑定

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter重新定义了对象获取属性值get()和设置属性值set()的操作来实现的。在数据变动时发布消息给订阅者,触发相应的监听回调,当属性被访问或改变时通知变化,而产生更新数据和视图。

  1. 需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter
    这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
  2. compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  3. Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:在自身实例化时往属性订阅器(dep)里面添加自己。自身必须有一个 update()方法。待属性变动 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。
  4. MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。

Vue的系统指令

  1. v-text可以将一个变量的值渲染到指定的元素中,如果数据中有HTML标签会将html标签一并输出
  2. v-text是纯文本,而v-html可以将HTML片段填充到标签中
  3. v-bind:用于绑定属性并响应地更新 HTML 属性。只能实现数据的单向绑定,从 M 自动绑定到 V
  4. v-on:事件绑定机制
  5. v-model:双向数据绑定
  6. v-for:根据数组中的元素遍历指定模板内容生成内容。
  7. v-if:设置元素的显示和隐藏(添加/删除DOM元素)
    作用:根据表达式的值的真假条件,来决定是否渲染元素,如果为false则不渲染(达到隐藏元素的目的),如果为true则渲染。
  8. v-show:设置元素的显示和隐藏(在元素上添加/移除style="display:none"属性)
  9. v-pre:显示原始信息跳过编译过程,跳过这个元素和它的子元素的编译过程。一些静态的内容不需要编译加这个指令可以加快渲染
  10. v-once:执行一次性的插值【当数据改变时,插值处的内容不会继续更新】

v-if/f-for的优先级,v-for就地复用原理

v-for和v-if不应该一起使用,必要情况下应该替换成computed属性。

   <li v-for="item in Nums" v-if="item%2==0">{{item}}->偶数</li>

原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。会影响性能增加渲染时长,我们可以在渲染之前把数据处理好:

filters: {
  Nums2: function(value) {
    return value.filter(i => i%2===0)
  }
}
// 或者
computed: {
  newNums() {
    return Nums.filter(i => i%2===0)
  }
}

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这个默认的模式是有效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。

v-if与v-show的区别

v-if和v-show都能够实现对一个元素的隐藏和显示操作。

区别:

  • v-if:每次都会重新添加/删除DOM元素
  • v-show:每次不会重新进行DOM的添加/删除操作,只是在这个元素上添加/移除style="display:none"属性,表示节点的显示和隐藏。

优缺点:

  • v-if:有较高的切换性能消耗。这个很好理解,毕竟每次都要进行dom的添加/删除操作。
  • v-show:有较高的初始渲染消耗。也就是说,即使一开始v-show=“false”,该节点也会被创建,只是隐藏起来了。而v-if="false"的节点,根本就不会被创建。v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。

总结:

  • 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show
  • 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符

常用的按键修饰符

.enter => enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) => 删除键
.esc => 取消键
.space => 空格键
.up => 上
.down => 下
.left => 左
.right => 右

Vue 中为什么使用key?

  1. 第一种情况是 v-if 中使用 key。由于 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。因此当我们使用v-if 来实现元素切换的时候,如果切换前后含有相同类型的元素,那么这个元素就会被复用。如果是相同的 input元素,那么切换前后用户的输入不会被清除掉,这样是不符合需求的。因此我们可以通过使用 key 来唯一的标识一个元素,这个情况下,使用 key 的元素不会被复用。这个时候 key 的作用是用来标识一个独立的元素。
  2. 第二种情况是 v-for 中使用 key。用 v-for 更新已渲染过的元素列表时,它默认使用“就地复用”的策略。如果数据项的顺序发生了改变,Vue 不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处的每个元素。因此通过为每个列表项提供一个 key 值,来以便 Vue 跟踪元 素的身份,从而高效的实现复用。这个时候 key 的作用是为了高效的更新渲染虚拟 DOM

用key来给每个节点做一个唯一标识
Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点,可以高效的更新虚拟DOM。

vue生命周期钩子函数

Vue实例从创建 到销毁的过程 ,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数在这里插入图片描述

创建期间的生命周期函数

  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
  • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始编译模板。我们可以在这里进行Ajax请求。
  • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
  • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示。(mounted之后,表示真实DOM渲染完了,可以操作DOM了)

运行期间的生命周期函数

  • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点
  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了。

销毁期间的生命周期函数

  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
  • destroyed:Vue 实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

什么时候需要使用beforeDestroy

  • 可能在当前页面中使用了$on方法,那需要在组件销毁前解绑
  • 清除自己定义的定时器
  • 解绑事件的绑定srcollmousemove…

vue中created、mounted、computed、methods区别与执行顺序

  • computed是在DOM执行完成后立马执行(如:赋值)
  • created执行时挂载阶段还没有开始,模版还没有渲染成html,所以无法获取元素。created钩子函数主要用来初始化数据
  • mounted钩子函数一般用来向后端发起请求,拿到数据后做一些业务处理。该函数在模版渲染完成后才被调用。DOM操作一般是mounted钩子函数中进行。
  • methods方法有一定的触发条件,如click等。
  • watch用于检测vue实例上数据的变动
  • 默认加载的时候先computed再watch,不执行methods;等触发某一事件后,则是:先methods再watch。所有方法都应该在methods里定义,在mounted或created里面使用this调用,用这种方法实现初始化

1.beforeCreate
在这个钩子函数前主要是对Vue实例进行属性的初始化

生命周期状态、监听器的初始化,这些与业务逻辑无关
处理父组件对本组件的自定义事件的监听,将其放到**_events**中
对创建VNode函数进行绑定,在Vue实例对象中,是不会存在直接对DOM进行操作的,而是通过创建VNode,然后通过patch的方式对DOM节点进行操作,操作的工具方法什么的跟原生一样的,Vue工具类里面包含对这些方法的封装。
对父组件传进来的属性(props)以及监听事件(v-on)进行深度观察
2.created
在这个钩子函数之前主要是对数据进行初始化并且进行监听操作:

Injection、provide选项进行初始化
对于用户定义的属性进行初始化,以下是按顺序来初始化,如果后面的属性名与前面相同的话,会报错:
props:传进来的属性是父组件过来的,这个属性不需要在子组件里面进行观察(因为父组件已经观察它了)
method:对设定的方法挂载到vm实例中,并且使用bind方法绑定函数上下文为vm对象,这也就是为什么我们使用箭头函数的方式的时候,也是能够通过this访问vm实例。
data:在选项的合并的时候将data处理成一个可执行的函数,这里的话,是将这个函数进行执行,得到组件的数据,并且将所有数据进行深度观测。
computed:创建一个lazy型的观察者,这个观察者是不会主动去触发的(如果计算属性是函数的话,每次需要拿到值的时候进行调用函数,如果是普通值的话,则会直接获取普通值)。这个计算属性是不能直接赋值操作的(getter方法被设置成一个空函数,所以怎么进行赋值也没有用),所以是个lazy型的观察者。computed的值只有在获取的时候才会执行然后拿到最新的值,所以它是一个懒求值。
watch:对传进来观察的对象的路径进行解析,拿到对应的属性。创建一个观察者,对这个属性进行观察,一旦属性发生变化的时候,会触发这个观察者,调用传进来的函数。
3.beforeMount
在挂载前的生命钩子前会进行元素绑定以及渲染函数的操作:

vm.$el属性赋值
渲染函数如果为空,进行创建空的方法
4.mounted
在本生命周期前,会进行渲染函数观察者的设定,当属性改变的时候,会直接反映到页面数据中。渲染函数观察者为什么要在数据观察者设定后进行创建的话,这个等到后面的讲述Vue的观察者篇章的时候再说。

这里要注意到一点,在创建观察者的时候,我们可以通过传给观察者一个before方法,这样执行观察者的函数前调用before方法。渲染函数观察者会传进一个before方法,这个方法只有一句话,就是将本组件的声明周期改为beforeUpdate,也就是说在修改数据的时候,反映到页面之前,组件会先进入到beforeUpdate生命周期。

5.beforeUpdate
上面一点也说明了,在beforeUpdate前是用户的各项操作,只要修改了某个属性值,那么就会触发这个生命周期钩子。

6.updated
触发beforeUpdate后,这时候是在清空调用观察者队列(queue是存放现在时间所有需要进行回调的观察者的一个队列,当然渲染函数观察者也在里面)。整个队列执行完毕后会进行调用这个updated生命周期函数,在调用这个生命周期函数的时候,页面重新渲染已经结束了,所以在updated生命周期钩子函数前会做以下事情:

打补丁(patch函数),这个函数首先是使用diff算法实现对dom操作的最小化,然后diff算法完成后,使用方法来针对于VNode修改dom节点内容。
重新绑定修改后的dom节点,你们可以在绑定vm对象的dom节点的属性上看到**__vue__这个属性,这个就是指向绑定的vm**。
7.beforeDestroy
仅仅是判断是否正在被destroy,使用变量锁(单线程下变量即可作为锁,无需使用原子操作)防止重复操作。

8.destroyed
这里主要是对事件、观察者的卸载,在这个生命周期钩子函数前会执行以下事情:

观察者的卸载(computed、watch、render)三个观察者进行卸载。
对根数据的观察者的卸载。
对VNode进行卸载,VNode的卸载会引发dom节点的删除。
9.destroyed之后
这里对于组件的产生的事件、监听的事情进行卸载,以及将对应的dom节点的**vue**属性设空,最后对父亲节点的解绑。。

组件传值

父组件向子组件传值

  • 父组件发送的形式是以属性的形式绑定值到子组件身上。
  • 然后子组件用属性props接收
  • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制
  <div id="app">
    <div>{{pmsg}}</div>
     <!--1、menu-item  在 APP中嵌套着 故 menu-item   为  子组件      -->
     <!-- 给子组件传入一个静态的值 -->
    <menu-item title='来自父组件的值'></menu-item>
    <!-- 2、 需要动态的数据的时候 需要属性绑定的形式设置 此时 ptitle  来自父组件data 中的数据 . 
		  传的值可以是数字、对象、数组等等
	-->
    <menu-item :title='ptitle' content='hello'></menu-item>
  </div>

  <script type="text/javascript">
    Vue.component('menu-item', {
      // 3、 子组件用属性props接收父组件传递过来的数据  
      props: ['title', 'content'],
      data: function() {
        return {
          msg: '子组件本身的数据'
        }
      },
      template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
    });
    var vm = new Vue({
      el: '#app',
      data: {
        pmsg: '父组件中内容',
        ptitle: '动态绑定属性'
      }
    });
  </script>

子组件向父组件传值 $emit+ v-on

  • 子组件用$emit()触发事件
  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
  • 父组件用v-on 监听子组件的事件

 <div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
     <!-- 2 父组件用v-on 监听子组件的事件
		这里 enlarge-text  是从 $emit 中的第一个参数对应   handle 为对应的事件处理函数	
	-->	
    <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      子组件向父组件传值-携带参数
    */
    
    Vue.component('menu-item', {
      props: ['parr'],
      template: `
        <div>
          <ul>
            <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
          </ul>
			###  1、子组件用$emit()触发事件
			### 第一个参数为 自定义的事件名称   第二个参数为需要传递的数据  
          <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
          <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button>
        </div>
      `
    });
    var vm = new Vue({
      el: '#app',
      data: {
        pmsg: '父组件中内容',
        parr: ['apple','orange','banana'],
        fontSize: 10
      },
      methods: {
        handle: function(val){
          // 扩大字体大小
          this.fontSize += val;
        }
      }
    });
  </script>

兄弟之间的传递 通过eventBus向中心事件发送或者接收事件,所有事件都可以共用事件中心

  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    • 提供事件中心 var hub = new Vue()
  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
  • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
 <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    //1、 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
       // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on(方法名
        hub.$on('tom-event', (val) => {
          this.num += val;
        });
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on()方法名
        hub.$on('jerry-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      },
      methods: {
        handle: function(){
          //4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据  
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>

Vuex

是一个专为 Vue.js 应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态,主要是为了多页面、多组件之间的通信。
Vuex有5个重要的属性,分别是 State、Getter、Mutation、Action、Module,由 view 层发起一个 Action 给 Mutation,在 Mutation 中修改状态,返回新的状态,通过 Getter暴露给 view层的组件或者页面,页面监测到状态改变于是更新页面。如果你的项目很简单,最好不要使用 Vuex,对于大型项目,Vuex 能够更好的帮助我们管理组件外部的状态,一般可以运用在购物车、登录状态、播放等场景中。

mutation action区别

Mutation:专注于修改State,理论上是修改State的唯一途径。必须同步执行

Action:业务代码、异步请求。可以异步,但不能直接操作State。

computed和watch有什么区别

  1. computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
  2. watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
  3. computed 是计算一个新的属性,并将该属性挂载到 Vue 实例上
  4. 而 watch 是监听已经存在且已挂载到 Vue 实例上的数据,所以用 watch 同样可以监听 computed 计算属性的变化。
  5. 只有当依赖变化后,第一次访问computed 属性,才会计算新的值。
  6. 而 watch 则是当数据发生变化便会调用执行函数。
  7. computed 适用一个数据被多个数据影响
  8. watch 适用一个数据影响多个数据

1.解释vue虚拟dom原理

(js操作dom速度很慢,操作js对象速度很快,把节点映射为一个js对象,此时js对象为虚拟dom,真正的dom位于哪个节点上,虚拟dom为映射的一个js对象,然后统一的操作dom。 )

每一个vnode都映射到一个真实的dom节点上。其中几个比较重要的属性:

tag 属性即这个vnode的标签属性
data 属性包含了最后渲染成真实dom节点后,节点上的class,attribute,style以及绑定的事件
children 属性是vnode的子节点
text 属性是文本属性
elm 属性为这个vnode对应的真实dom节点
key 属性是vnode的标记,在diff过程中可以提高diff的效率,后文有讲解
比如,我定义了一个vnode,它的数据结构是:

{
    tag: 'div'
    data: {
        id: 'app',
        class: 'page-box'
    },
    children: [
        {
            tag: 'p',
            text: 'this is demo'
        }
    ]
}

最后渲染出的实际的dom结构就是:

 <div id="app" class="page-box">
       <p>this is demo</p>
   </div>

2.解释双向数据绑定

首先要对数据进行劫持监听,所以我们首先要设置一个监听器Observer,用来监听所有的属性,当属性变化时,就需要通知订阅者Watcher,看是否需要更新.因为属性可能是多个,所以会有多个订阅者,故我们需要一个消息订阅器Dep来专门收集这些订阅者,并在监听器Observer和订阅者Watcher之间进行统一的管理.以为在节点元素上可能存在一些指令,所以我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令初始化成一个订阅者Watcher,并替换模板数据并绑定相应的函数,这时候当订阅者Watcher接受到相应属性的变化,就会执行相对应的更新函数,从而更新视图.

整理上面的思路,我们需要实现三个步骤,来完成双向绑定:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

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

3.解释render作用

在vue中我们使用模板HTML语法组建页面的,使用render函数我们可以用js语言来构建DOM

4.解释slot作用

目的是用在内容分发
在组件添加一个占位的空间,在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动替换组件模板中

6.VUE生命周期解释

每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。

实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作

挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情…

当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿

当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom

当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

组件的数据绑定、监听…去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

深入理解响应式原理:

当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

vue组件中的data为什么必须是一个函数?

如果不用函数的话,实例化的组件是共享同样的一个data对象,当你修改一个属性的时候,data也改变。

当data是一个函数的时候,每个实例的data属性都是独立的,不会相互影响。

虚拟DOM

首先对我们将要插入到文档中的 DOM 树结构进行分析,使用 js 对象将其表示出来,比如一个元素对象,包含 TagName、props 和 Children 这些属性。然后我们将这个 js 对象树给保存下来,最后再将 DOM 片段插入到文档中。
当页面的状态发生改变,我们需要对页面的 DOM 的结构进行调整的时候,我们首先根据变更的状态,重新构建起一棵对象树,然后将这棵新的对象树和旧的对象树进行比较,记录下两棵树的的差异。
最后将记录的有差异的地方应用到真正的 DOM 树中去,这样视图就更新了。

vue常用的修饰符

.prevent: 提交事件不再重载页面
.stop: 阻止单击事件冒泡
.self: 当事件发生在该元素本身而不是子元素的时候会触发
.capture: 事件侦听,事件发生的时候会调用

Vue的渲染过程

1、把模板编译为render函数

2、实例进行挂载, 根据根节点render函数的调用,递归的生成虚拟dom

3、对比虚拟dom,渲染到真实dom

4、组件内部data发生变化,组件和子组件引用data作为props重新调用render函数,生成虚拟dom, 返回到步骤3

Vue中的模板编译原理

将template转化成render函数

对 Vue 项目可以进行哪些优化?

代码层面的优化:

v-if 和 v-show 区分使用场景
computed 和watch 区分使用场景
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
长列表性能优化
事件的销毁
图片资源懒加载
路由懒加载
第三方插件的按需引入
优化无限列表性能
服务端渲染 SSR or 预渲染

Webpack 层面的优化:

Webpack 对图片进行压缩
减少 ES6 转为 ES5 的冗余代码
提取公共代码
模板预编译
提取组件的 CSS
优化 SourceMap
构建结果输出分析

Vue 项目的编译优化

基础的 Web 技术的优化:

1.开启gzip 压缩

2.浏览器缓存

3.CDN的使用

4.使用 Chrome Performance 查找性能瓶颈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值