Vue相关

1.Vue中监听路由参数变化

问题:当在同一路由下,只是后面参数发生变化时,页面并不会刷新,但此时想获取新数据怎么办?
解决:使用watch监听路由变化

//例当路由后面的name参数发生变化时
watch(){
  $route() {
    this.name = this.$route.query.name;
    console.log(this.name);
  }
}

2.Vue打包后部署到express服务器上

首先通过

npm run build

将vue项目打包,打包完成会生成一个dist文件夹,将此文件夹内的所有文件和文件夹拷贝到express的pubilic目录先,然后通过

node app.js

开启express服务即可

3.vuex报错Uncaught Error: [vuex] store must be called with the new operator.

原因:在使用Vuex.Store()的时候忘记加上new了
更改前:

const store = Vuex.Store({  //Vuex前面少了new
    modules:{
        user
    }
})

更改后:

const store = new Vuex.Store({
    modules:{
        user
    }
})

4. vue中在beforeDestroyed,destroyed和unactived钩子函数中scrollTop一直为0的问题

外不包裹时,在beforeDestroyed,destroyed和unactived钩子函数中获取scrollTop值恒为0,无论是document.body.scrollTop,document.documentElement.scrollTop还是window.scrollY,其值一直为0,到现在我也没弄清楚原因。
解决办法有如下两种方案:
方案一:

//在外层包裹标签,正好设置相应动画效果

    

方案二:
在beforeRouteLeave函数中获取scrollTop的值,此时获取的值是正确的

5.Vue实现点击,长按,滑动共存

利用@touchstart,@touchmove,@touchend和setTimeout实现,完整代码如下:






6.源码解析

数据劫持.png

Vue是MVVM框架,即model,view,view model框架。
Vue通过数据劫持+发布订阅者模式完成数据变化监听及视图更新

Compile解析过程:
Vue为了减少重绘与回流,利用DocumentFragment(文档节点碎片)将所有节点存入内存中,DocumentFragment不是真实DOM树的一部分,因此其中内容发生变化不会因此DOM树重新渲染。
然后对DocumentFragment中每个节点进行解析,获取相应指令,如v-model,v-text,v-on(@),v-bind(:)等,然后采取相应处理。
处理完后再追加回节点位置。
在解析同时订阅数据变化,即添加相应watcher。

Observer劫持属性过程:
利用Object.defineProperty对data对象所有属性进行遍历劫持,添加get和set方法,注意修改新值前需要对新值进行劫持,否则修改后新值将不再被劫持。

Dep:
数据劫持后每次访问数据,都会调用相应get方法。
对数据添加watcher时会访问相应数据,访问数据前将watcher赋值给Dep一个target属性,即Dep.target=this(此时this即watcher实例)。然后将此watcher放入Dep中存储,此时需注意添加完成后需将Dep.target=null,否则后续访问数据将持续新增watcher。

Watcher:
Compile解析完成后会调用相应update函数(例如v-text对应的update.text函数)初始化视图,完成视图更新。因此在Compile过程中添加相应watcher后,当数据发生变化时即可通过回调函数返回新值。此时再调用相应update函数触发视图更新。

model双向绑定,视图=>数据=>视图:
编译时,在相应更新方法update.model中对input组件添加input监听事件,当视图中input数据发生变化时,就去改变data中的数据。而当data中的数据改变后,又会去触发相应watcher去驱动视图改变。

总结:
Vue通过数据劫持结合发布-订阅者模式来完成数据监听和视图更新。利用Object.defineProperty方法来劫持data中的数据的getter和setter方法。当数据发生变化时,通过依赖采集器通知watcher进行视图更新。

通过一个Vue实例为入口,使用Compile来编译模板,同时添加Watcher,并将Watcher挂载到Dep上。使用Observer利用Object.defineProperty劫持数据的getter和setter方法,在通过getter方法获取数据时,将挂载到Dep的Watcher存储到实例化dep中,通过Watcher将Compile和Observer联系起来。当利用setter方法改变数据时,Observer通知Watcher数据发生变化,Watcher通过回调利用Compile实现视图更新。利用添加事件监听器来完成双向绑定,当视图中内容发生变化时,利用setter方法改变模型中相应数据,数据变化又会通知Watcher从而更新视图。

7.深度监听

监听对象内部属性值时,需要添加deep为true,否则watch无法监听对象属性值发生变化,但是这样非常耗性能




    
    
    Vue


    
FullName: {{person.fullname}}
FirstName:

8.computed和watch区别

computed: 返回计算得到的值,会被缓存,只有当被计算的值发生变化时才会重新计算。
watch: 对已有的值进行监听,当监听的值发生变化时执行相应操作。
最大区别就是computed是通过计算已有的值返回一个值,属于多个值影响一个值。而watch是监听已有的值的变化进而进行操作,属于一个值影响多个值
注意:不要在computed和watch中修改被计算或被监听的值,否则可能形成无限循环

9.vue scoped实现原理

通过给相应组件内每个DOM节点添加一个data属性,类似data-v-47323bf2,然后在style中添加对应属性选择器来选中该DOM,实现内部样式,不会污染全局

10.Vue和React

都是基于JavaScript的框架
React生态更完善,更成熟
React更注重人为控制,Vue更考虑使用者方便

11.vue中为什么只有根实例data是一个对象,component中data必须是函数

因为component实例可能有多个,如果data是一个对象的话,会导致多个实例共用一个data,相互影响。而根实例只有一个,不会被影响。

12.this.$nextTick()实现原理

vue所有数据更新在主线程完成,生成一个执行栈,数据变化后并不是立即更新DOM,而是异步开启一个队列,缓冲所有数据变化,当一个watcher被触发多次时,只会被放入队列一次。
当执行完主线程执行栈中的操作后,查找异步队列推入执行栈。Vue内部使用Promise或 MessageChannel来对异步操作进行处理,如果环境不支持则采用setTimeout方式。
DOM更新完成后,执行nextTick

13.vue-router实现原理

两种模式(mode):hash和history
#后的内容称为hash,是用来指导浏览器动作的,虽然在URL中但不会对服务器进行请求,通过window.location.hash可以改变hash并在历史中添加一个记录,然后改变_route的值,当_route改变时自动更新视图。而当直接改变地址栏hash时,vue-router自身添加了hashchange事件,当监听到hash变化时更新视图。

history模式采用了HTML5新特性,history.pushState用来改变浏览器的历史记录栈,基本原理与hash相同,监听地址栏变化使用的是onpopstate事件。当浏览器不支持HTML5特性时自动转为hash方式。

14.vuex实现原理

将vuex作为一个插件使用Vue.use安装到Vue中,使用Vue.use()安装插件时需要调用install方法,install方法执行时会将Vue作为参数传入。

基本实现方法:
利用Vue.mixin({beforeCreate(){}})为每个Vue实例或子组件混入一个beforeCreate()钩子函数,这样当安装完这个插件后,每次进行Vue实例化或者创建子组件时,都会调用这个钩子函数,此时this指向Vue实例或创建的子组件。
在混入的钩子函数中查看Vue实例或子组件的父组件是否包含store属性,包含的话将此属性值赋给此实例或子组件,这样就可以随处调用store
在定义的Store类的构造函数中创建Vue实例,将store实例上的state绑定到此Vue实例的data上,这样即可借用Vue自动监测state变化,并相应更新视图。然后将传入的getter,mutations,actions等方法添加到store实例上。

15.渐进式响应系统

可以通过添加模块一点点完成一个系统
为什么使用框架:
框架能够将真实DOM映射到虚拟DOM,当数据发生变化时能够通过各自的算法智能计算出重新渲染的最小代价,并自动更新视图,不需要再人为去考虑如何更新DOM,提高了开发效率
将视图,数据,控制代码分开,更有条理性,代码更易维护

组件化,可以独立开发组件,提高复用性
数据,视图,逻辑分离,逻辑更加清晰
操作虚拟DOM而不是直接操作DOM,一定程度上提高效率

16.Vue虚拟DOM和diff算法

Vue通过一个函数将template模板中的元素转换为对应的虚拟节点vNode(一个对象,用来描述真实节点),构成虚拟DOM树。在数据发生变化时,利用diff算法对比新旧vNode树,计算出重新渲染的最小代价,然后调用相应更新函数去更新虚拟节点。最后通过一个函数可以将虚拟节点渲染成真实DOM。
diff算法比较策略:深度优先,同级比较
同级节点会先判断他们是否含有子节点或文本节点,不同节点不同操作,比如不同文本节点,则使用新文本去替代旧文本;子节点比较是重点,设置头尾两个指针,会首先进行四种比较(头头,尾尾,头尾,尾头)看是否有相同节点,否则循环遍历查找相同节点,同时指针向中间移动。旧子节点和新子节点总会有一个先遍历完,若旧子节点先遍历完说明需新增了子节点,若新节点先遍历完说明需要删除子节点,批量处理这些节点。key值很关键,有独一无二的key能够快速定位相同节点。
在v-for中key是很有用的,不要使用index作为key,而是要采用不同的数据属性值作为key,因为在diff算法中会根据这些key去进行比较,当插入或删除元素时,根据key进行比较可以避免不必要的渲染。

17.Vue劫持数组

通过改写Array原生函数,pop,push,shift,unshift,splice,当调用这些函数修改数组时,通知watcher更新视图

18.MVC MVP MVVM

传统MVC是前端负责实现视图然后交由后端处理渲染,后来前后端分离,形成前端MVC框架。MVC指的是Model(数据),View(视图),Controller(控制),当视图发生变化时通知控制,控制改变数据,数据再去更新视图。

MVP,Model,View,Presenter,常用于安卓原生开发。通过Presenter将Model和View更好的分开,但可能导致Presenter过于臃肿,不易维护。

MVVM双向绑定,Model,View,ViewModel,VM自动响应数据变化,并根据数据变化更新视图。不需要再认为去操作DOM,提高了开发效率。

18.mixin

mixin提供一种混入功能,可以将任意data,生命周期函数或methods等混入Vue组件中。
data与组件中data进行递归合并,当数据冲突时以组件数据优先
methods等对象选项与组件合并时,混合为同一个对象,键值相同时以组件中的值为准
钩子函数合并时,合并为一个数组,均会执行,且mixin中钩子函数先执行,组件中钩子函数后执行

19.directives

通过directives添加自定义指令
全局添加:

Vue.directive('name', {
  //el:绑定的元素,binding:绑定的内容,如binding.name为focus,binding.value为绑定的值,vnode:生成的虚拟节点(要在自定义指令中调用this,可通过_this=vnode.context得到),oldnode:更新前的旧节点
  bind: function(el, binding, vnode, oldnode) {  
    //绑定时调用
  },
  inserted: function(el, binding, vnode, oldnode) {
    //元素插入时调用
  },
  update: function(el, binding, vnode, oldnode) {
    //组件更新时调用
  },
  componentUpdated: function(el, binding, vnode, oldnode) {
    //组件更新完成时调用
  },
  unbind: function(el, binding, vnode, oldnode) {
    //解绑时调用
  },
})

局部添加:

directives: {
  focus: {
    bind: (el, binding, vnode, oldnode) => {} //同样有五个生命周期
    inserted: (el, binding, vnode, oldnode) => {}
    update: (el, binding, vnode, oldnode) => {}
    componentUpdated: (el, binding, vnode, oldnode) => {}
    unbind: (el, binding, vnode, oldnode) => {}
  }
}

20.组件传值

父子组件传值:
父组件在调用子组件时绑定属性值,子组件通过props接收父组件传递过来的值。
子组件通过emit事件向父组件传值,父组件在调用子组件时绑定相应函数,利用该函数接收子组件传递过来的值

provided和inject,祖孙间传值,无论多少层都能传值

兄弟组件传值:
vuex:统一状态管理

EventBus:利用Vue实例实现事件发送和监听,从而完成传值
新建一个EventBus类,其中包含_events属性,用来存储各种监听事件及其回调函数,类中包含on(添加监听),emit(发送消息),off(移除监听)等函数
on:添加监听函数到_events中,可能为一个函数,也可能为函数数组
emit:发送消息,发送消息后去_events中匹配对应监听函数或函数数组,若只有一个函数则执行该函数,若为函数数组,则遍历执行整个函数数组的函数
off:移除相应监听函数

21.Vue更新队列

Vue修改数据时并不会立即进行视图更新,而是类似js事件队列,生成一个异步更新队列,当同步代码执行完毕后再去更新视图,同时做去重处理,即一个数据被修改多次,最终只执行一次,提升性能.
$nextTick执行时机在DOM更新完毕后

你可能感兴趣的:(Vue相关)