爬vue

作者: 混水妹妹 | 来源:发表于2021-03-13 14:25 被阅读0次

    1、$nextTick

    (1)原理
    说法一:
    Vue在更新DOM时是异步执行的。
    只要监听到数据变化,vue就会开启一个队列,并缓冲在同一事件循环中发生的所有数据变化。
    如果同一个监听,被多次触发了,只会被推入队列一次。这种会在缓冲时去除重复数据,避免不必要的计算和DOM操作。
    这样是为了提高性能,因为主线程中更新DOM,循环100次就要更新100次DOM,如果事件循环之后,就只需要更新一次。
    为了数据更新操作之后操作DOM,那在数据变化之后,用Vue.$nextTick,这样回调函数会在DOm更新完成后被调用,就可以拿到最新的DOM元素了

    说法二:
    由于Vue DOM更新是异步执行的,
    即修改数据时,视图不会立即更新,而是会监听数据变化,
    并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。
    这样是为了提高性能,因为在主线程中更新DOM,循环100次,就要更新100次DOM,如果事件循环完之后,就只需要更新一次。
    为了确保得到更新后的DOM,就用$nextTick

    应用场景:
    (1)在created钩子函数中,要进行DOM操作
    在created钩子函数,DOM都还没有渲染,所以此时要进行DOM操作的话,就要用到nextTick 在工作中,后台管理系统,在created请求数据,并进行页面渲染时,要勾选上表格复选框的值,进行此操作要放到nextTick中
    (2)要改变DOM元素结构时,对DOM进行的操作都要放到$nextTick的回调函数中。

    2、新技术

    vite (打包机,热加载很快,比webpack要快)

    3、vue项目,为什么要在列表组件中写key,作用是?

    (1)渲染真实的dom开销很大,如果修改某个数据,在vue中,采用diff算法,diff算法就会比较新旧节点的变化,如果某个节点修改了,就重新渲染节点,其它节点就复用旧节点,这样大大减少了开销,diff算法只会比较同一层次的节点。
    (2)如果节点类型不同,直接干掉前面的节点了,并创建,插入新节点,不会再比较这个节点的子节点了。
    (3)当要插入一条数据时,节点都有key值为唯一标识,那么diff算法就可以正确识别此节点,找到正确的位置插入新的节点。

    总:需要使用key来给每个节点做唯一标识,Diff算法就可以正常识别些节点。
    主要为了高效的更新虚拟DOM。

    4、vue的自定义指令(待看)

    自定义指令分为全局指令和组件指令,其中全局指令需要使用directive来进行定义,组件指令需要使用directives来进行定义,具体定义方法同过滤器filter或者其他生命周期,具体使用方法如下:

    全局自定义指令 directive(name,{}),其中name表示定义的指令名称(定义指令的时候不需要带v-,但是在调用的时候需要哦带v-),第二个参数是一个对象,对象中包括五个自定义组件的钩子函数,具体包括:

    bind函数:只调用一次,指令第一次绑定在元素上调用,即初始化调用一次,

    inserted函数:并绑定元素插入父级元素(即new vue中el绑定的元素)时调用(此时父级元素不一定转化为了dom)

    update函数:在元素发生更新时就会调用,可以通过比较新旧的值来进行逻辑处理

    componentUpdated函数:元素更新完成后触发一次

    unbind函数:在元素所在的模板删除的时候就触发一次

    钩子函数对应的参数el,binding,vnode,oldnode,具体参数讲解如下:

    a、el指令所绑定的元素 可以直接操组dom元素

    b、binding一个对象,具体包括以下属性:

    1)name:定义的指令名称 不包括v-

    2)value:指令的绑定值,如果绑定的是一个计算式,value为对应计算结果

    3)oldvalue:指令绑定元素的前一个值,只对update和componentUpdated钩子函数有值

    4)expression:指令绑定的原始值 不对值进行任何加工

    5)arg:传递给指令的参数

    6)modifiers:指令修饰符,如:v-focus.show.async 则接收的modifiers为{show:true,async:true}

    c、vnode:vue编译生成的虚拟dom

    d、oldVnode:上一个vnode,只在update和componentUpdated钩子函数中有效

    ⚠️:如果不需要其他钩子函数,可以直接简写为:directive(“focus”,function(el,binding){})

    5、vue的实现原理

    vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

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

    6、vue的diff算法理解

    (1)diff算法的作用:用来修改dom的一小段,不会引起dom树的重绘
    (2)diff算法的实现原理:diff算法将wirtual dom(虚拟dom)的某个节点数据改变后生成的新的vnode与旧节点进行比较,并替换为新的节点,具体过程就是调用patch方法,比较新旧节点,一边比较一边给真实的dom打补丁进行替换
    (3)diff算法是:(eno)
    diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
    (4)具体过程详解

    a、在采用diff算法进行新旧节点进行比较的时候,比较是按照在同级进行比较的,不会进行跨级比较:


    image.png

    b、当数据发生改变的时候,set方法会调用dep.notify通知所有的订阅者watcher,订阅者会调用patch函数给响应的dom进行打补丁,从而更新真实的视图

    c、patch 函数接受两个参数,第一个是旧节点,第二个是新节点,首先判断两个节点是否值得比较,值得比较则执行patchVnode函数,不值得比较则将旧节点替换为新节点。如果两个节点一样就直接检查对应的子节点,如果子节点不一样就说明整个子节点全部改变不再往下对比直接进行新旧节点的整体替换

    d、patchCVnode函数:找到真实的dom元素;判断新旧节点是否指向同一个对象,如果是就直接返回;如果新旧节点都有文本节点,那么直接将新的文本节点赋值给dom元素并且更新旧的节点为新的节点。如果旧节点有子节点再新节点没有,则直接删除dom元素中的子节点;如果旧节点没有子节点,新节点有子节点,那么直接将新节点中的子节点更新到dom中;如果两者都有子节点,那么继续调用函数updateChildren

    e、updateChildren函数:抽离出新旧节点的所有子节点,并且设置新旧节点的开始指针和结束指针,然后进行两辆比较,从而更新dom(调整顺序或者插入新的内容,结束后删除多余的内容)

    7、vue的路由模式及区别、底层原理

    vue-router有2种模式来实现页面跳转
    1.hash模式
    hash模式是通过利用url中的hash值来实现路由,而hash值的变化是不会刷新页面。
    hash底层原理:通过window.onhashchange事件监听url上的hash值变化,然后获取hash值(window.location.hash),根据hash值分别把不同组件内容渲染到router-link标签上,该方法必须在服务器环境下运行。
    注:onhashchange 事件在当前 URL 的锚部分(以 '#' 号为开始) 发生改变时触发 。

    2、history模式
    history模式根据html5新增的2个方法pushState和replaceState来实现路由,而且2种方法修改url时不会刷新页面(路由没有带’#‘,需要后端支持)
    history router底层原理
    根据路由变化调用 pushState()和replaceState()方法修改url,通过window.onpopstate事件监听url的变化分别把不同组件的内容渲染到router-link标签上。

    hash模式在浏览器中符号”#“,#以及#后面的字符称之为hash,用window.location.hash读取。
    特别:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。

    history模式:history受用HTML5的新特性;
    提供了两个新方法:pushState(),replaceState() 可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history模式下,前端的URL必须和实际向后端发起请求的URL一致,否则会报404错误

    8、组件通信

    (1)子传父
    emit
    (2)父传子
    props
    (3)兄弟传(有共同的父亲)
    (4)vuex 刷新数据会丢失
    vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
    (5)ref (6)slot (7)路由通信 (8)多级组件嵌套组件通信attrs/$listeners

    image.png

    9、vue的MVVM的理解

    MVVM 是Model-View-ViewMode的缩写
    Mode:代表数据模型,主要用于定义数据和操作业务逻辑
    View:代表页面展示组件,视图
    ViewModel为mode和view的桥梁,监听模型数据改变和控制视图行为,处理用户交互。
    通过双向数据绑定把View和Model层连接起来,

    在MVVM架构中,View和Model之前并没有直接的联系,而是通过ViewModel进行交互,Model和ViewModel之前的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。

    image.png

    10、vue实现的原理

    vue.js是采用数据劫持结合发布者-订阅者模式的方法,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时,发表信息给订阅者,触发相应的监听回调。
    具体步骤:
    第一步:需要observe(观察)的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter
    这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

    第二步:compile解析模块指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

    第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
    1.1在自身实例化时往属性订阅dep里面添加自己
    2.2自身必须有一个update()方法
    3.3待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

    第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的mode数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -》视图更新;视图交互变化(input)-》数据model变更的双向数据绑定效果。

    11、vue与react、angular的比较?

    Vue

    轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;
    简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
    双向数据绑定:保留了angular的特点,在数据操作方面更为简单;
    组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势;

    视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
    虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式;
    运行速度更快:相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。

    React

    相同点:
    React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。

    不同点:
    React采用的Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。
    (通俗,react没有指令)
    Angular

    相同点:
    都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。

    不同点:
    AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。

    12、vue-roter的钩子函数

    vue路由钩子大致可以分为三类

    (1)全局钩子
    主要包括beforeEach和afterEach,
    beforeEach函数有三个参数:
    to:router即将进入的路由对象
    from:当前导航即将离开的路由
    next:Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是confirmed(确认的);否则为false,终止导航。
    afterEach函数不用传next()函数这类钩子主要作用于全局,一般用来判断权限,以及页面丢失时候需要执行的操作,例如:

    
    //使用钩子函数对路由进行权限跳转
    router.beforeEach((to, from, next) => {
        const role = localStorage.getItem('ms_username');
        if(!role && to.path !== '/login'){
            next('/login');
        }else if(to.meta.permission){
            // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
            role === 'admin' ? next() : next('/403');
        }else{
            // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
            if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){
                Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,
                请使用更高版本的浏览器查看', '浏览器不兼容通知', {
                    confirmButtonText: '确定'
                });
            }else{
                next();
            }
        }
    })
    

    (2)单个路由里面的钩子
    主要用于写某个指定路由跳转时需要执行的逻辑

    (3)组件路由
    主要包括beforeRouteEnter和beforeRouteUpdate,beforeRouteLeave,这几个钩子都是写在组件里面也可以传三个参数(to,from,next),作用与前面类似

    beforeRouteEnter(to, from, next) {
        next(vm => {
          if (
            vm.$route.meta.hasOwnProperty('auth_key') &&
            vm.$route.meta.auth_key != ''
          ) {
            if (!vm.hasPermission(vm.$route.meta.auth_key)) {
              vm.$router.replace('/admin/noPermission')
            }
          }
        })
      }
    

    13、vuex的使用

    (1)vuex是什么
    Vuex 是Vue.js 的状态管理模式,集中管理和存储所有应用组件的状态。也是跨组件通信的一种方式,具体包括:

    (2)vuex的属性
    1)state:
    存放的数据状态,不可以直接修改里面的数据。
    Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。

    2)getter:state的计算属性,类似vue的计算属性,主要用来过滤一些数据。

    3)actions:actions可以理解为通过将mutations里面处理数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。可以异步函数调用

    4)mutation:mutations定义的方法动态修改Vuex 的 store 中的状态或数据

    5)modules:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

    (3)vuex解决了什么问题
    1)多个组件依赖同一状态时,多层嵌套的组件非常繁琐,并对兄弟组件间通信无能为力时。
    2)不同组件的行为需要改变同一状态。

    (4)vuex的应用场景
    多个组件依赖同一状态时
    来自不同组件的行为需要变更同一状态

    (5)怎么引入vuex
    1)先安装依赖cnpm i vuex --save
    2)在项目目录src中建立store文件夹
    3)在store文件夹下新建index.js文件,写入

    import Vue from 'vue';
    import Vuex from 'vuex';
    Vue.use(Vuex);
    //不是在生产环境debug为true
    const debug = process.env.NODE_ENV !== 'production';
    //创建Vuex实例对象
    const store = new Vuex.Store({
      strict:debug, //在不是生产环境下都开启严格模式
      state:{},
      getters:{},
      mutations:{},
      actions:{}
    })
    export default store
    

    然后再main.js文件中引入vuex,这么写

    import Vue from 'vue';
    import App from './App.vue';
    import store from './store';
    const vm = new Vue({
        store:store,
        render: h => h(App)
    }).$mount('#app')
    
    

    4)vuex中状态储存在哪里,怎么改变它?
    存储在state中,改变vuex中的状态唯一途径就是提交mutation

    5)vuex中状态是对象时,使用时要注意什么
    因为对象是引用类型,复制后改变属性会影响原始数据,这样会改变state里面的状态,是不允许的,所以先用深度克隆复制对象,再修改。

    6)vuex有个特点 刷新页面 数据会丢失
    再加个mapstate...

    14、vue的filter的理解与用法

    1)全局过滤器必须写在vue实例创建之前

    Vue.filter('testfilter', function (value,text) { // 返回处理后的值
       return value+text
       })
    

    (2)局部写法:在组件实例对象里挂载。

    filters: {
            changemsg:(val,text)\=>{ return val + text
            }
        }
    

    (3)使用方式:只能使用在{{}}和:v-bind中,定义时第一个参数固定为预处理的数,后面的数为调用时传入的参数,调用时参数第一个对应定义时第二个参数,依次往后类推

    <h3 :title="test|changemsg(1234)">{{test|changemsg(4567)}}</h3>  
    //多个过滤器也可以串行使用  
    <h2>{{name|filter1|filter2|filter3}}</h2>
    

    (4)vue-cli项目中注册多个全局过滤器写法:

    
    //1.创建一个单独的文件定义并暴露函数对象
    const filter1 = function (val) {
      return val + '--1'
    }
    const filter2 = function (val) {
      return val + '--2'
    }
    const filter3 = function (val) {
      return val + '--3'
    }
    
    export default {
      filter1,
      filter2,
      filter3
    }
    
    //2.导入main.js(在vue实例之前)
    import filters from './filter/filter.js'
    
    //3.循环注册过滤器
    Object.keys(filters).forEach(key=>{
      Vue.filter(key,filters[key])
    })
    

    15、vue的keep-alive的理解?

    keep-alive 是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
    页面第一次进入,钩子的触发顺序:created-> mounted-> activated,退出时触发 deactivated ,
    当再次进入(前进或者后退)时,只触发activated事件挂载的方法等,
    只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;
    其有几个属性如下:

    1)include - 字符串或正则表达式,只有名称匹配的组件会被缓存
    2)exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存
    3)include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。
    注:匹配首先检查组件自身的 name 选项
    不会在函数式组件中正常工作,因为它们没有缓存实例
    当组件在内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行

    
    <!-- 逗号分隔字符串,只有组件a与b被缓存。-->
    <keep-alive include="a,b">
      <component></component>
    </keep-alive>
    
    <!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) -->
    <keep-alive :include="/a|b/">
      <component></component>
    </keep-alive>
    
    <!-- Array (需要使用 v-bind,被包含的都会被缓存) -->
    <keep-alive :include="['a', 'b']">
      <component></component>
    </keep-alive>
    

    16、vue首屏白屏如何解决?
    1)路由懒加载
    2)vue-cli开启打包压缩 和后台配合 gzip访问
    3)进行cdn加速
    4)开启vue服务渲染模式
    5)用webpack的externals属性把不需要打包的库文件分离出去,减少打包后文件的大小
    6)在生产环境中删除掉不必要的console.log

    plugins: [
        new webpack.optimize.UglifyJsPlugin({ //添加-删除console.log
          compress: {
            warnings: false,
            drop_debugger: true,
            drop_console: true
          },
          sourceMap: true
        }),
    
    

    7)开启nginx的gzip ,在nginx.conf配置文件中配置

    
    http {  //在 http中配置如下代码,
       gzip on;
       gzip_disable "msie6"; 
       gzip_vary on; 
       gzip_proxied any;
       gzip_comp_level 8; #压缩级别
       gzip_buffers 16 8k;
       #gzip_http_version 1.1;
       gzip_min_length 100; #不压缩临界值
       gzip_types text/plain application/javascript application/x-javascript text/css
        application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
     }
    

    8)添加loading效果,给用户一种进度感受

    17、v-model的理解(原理)?

    答:v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
    1)v-bind绑定一个value属性;
    2)v-on指令给当前元素绑定input事件

    18、computed和watch的用法和区别?

    computed
    1)变量不在 data中定义,而是定义在computed中,写法跟写方法一样,有返回值。函数名直接在页面模板中渲染,不加小括号 。
    2)根据传入的变量的变化 进行结果的更新。
    3)计算属性基于响应式依赖进行缓存。如其中的任意一个值未发生变化,它调用的就是上一次计算缓存的数据,因此提高了程序的性能。而methods中每调用一次就会重新计算一次,为了进行不必要的资源消耗,选择用计算属性。

    watch

    1)计算属性的时候 初始化的时候就可以被监听到并且计算 但是watch是发生改变的时候才会触发。
    2)当有一些数据需要随着其它数据变动而变动时,或者当需要在数据变化时执行异步或开销较大的操作时,使用 watch。

    总结:

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

    18、$nextTick的使用?

    答:在vue中理解修改数据后,对应的dom需要一定的时间进行更新,因此为了能够准确的后去更新后的dom,可以采用延迟回调的方法进行更新dom的获取,所以出现了$nextTick来进行延迟回调。即:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

    19、data为什么是一个函数?

    答:这是有JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
    组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。

    20、vue单页面和传统的多页面区别?

    单页面应用(SPA)

    通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

    多页面(MPA)

    指一个应用中有多个页面,页面跳转时是整页刷新

    单页面的优点:

    用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。

    单页面缺点:

    不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。

    21、vue常用的修饰符?

    .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
    .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
    .capture:与事件冒泡的方向相反,事件捕获由外到内;
    .self:只会触发自己范围内的事件,不包含子元素;
    .once:只会触发一次。

    22、vue开发遇到的问题?

    1)样式污染

    答:在编写样式中,如果需要防止样式的污染,可以使用两种方式,一种是在组件的根元素上增加一个唯一的class或者id,然后在编写组件的样式时候在根元素对应的class或者id下进行编写;另一种方式是在对应的style上添加scoped关键字,不过该关键字对引用的框架UI无效

    2)router-link在安卓上不起作用

    答:不起作用的原因是因为转码编译的问题,可以使用babel来进行处理,安装babel polypill插件解决

    3)初始化页面出现闪屏乱码的问题

    答:这是因为vue还没有解析的情况下会容易出现花屏现象,看到类似于{{data}}的字样,可以使用两种方式来进行处理,一种为:在设置index.html的根元素的元素的样式为display:none,然后在mounted中的$nextTick函数中display:block展示;另一种方式是使用vue的内置指令:v-cloak,并且在css中设置样式

    [v-cloak] {
    display: none;
    }
    4)router-link上事件无效解决方法

    答:使用@click.native来进行调用原生的js事件。原因:router-link会阻止click事件,.native指直接监听一个原生事件。

    23、vue的solt的用法?

    在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个slot(插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的<slot> 标签及它的内容。

    简单说来就是:在子组件内部用 <slot></slot>标签占位,当在父组件中使用子组件的时候,我们可以在子组件中插入内容,而这些插入的内容则会替换 <slot></slot>标签的位置。

    当然:单个solt的时候可以不对solt进行命名,如果存在多个 则一个可以不命名,其他必须命名,在调用的时候指定名称的对应替换slot,没有指定的则直接默认无名称的solt

    24、路由跳转和location.href的区别?

    使用location.href='/url'来跳转,简单方便,但是刷新了页面;
    使用路由方式跳转,无刷新页面,静态跳转;

    25、为什么组件中data必须用函数返回一个对象()

    对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。

    26、组件中 data 为什么是一个函数

    为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象?

    因为组件是用来复用的,js里对象是引用类型,如果组件中data是一个对象,那种这样作用域没有隔离,子组件中的data属性会相互影响,
    如果组件中data选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的data属性值不会互相影响;
    而new Vue的实例,是不会被复用的,因此不存在引用对象问题。

    27、说说你对组件插槽的理解

    28、vue怎么定义全局方法

    (1)挂载在Vue的prototype上

    // base.js
    const install = function (Vue, opts) {
        Vue.prototype.demo = function () {
            console.log('我已经在Vue原型链上')
        }
    }
    export default {
        install
    }
    
    
    //main.js
    //注册全局函数
    import base from 'service/base';
    Vue.use(base);
    

    (2)利用全局混入mixin
    (3)用this.root.on绑定方法,用this.root.off解绑方法,用this.root.emit全局调用。

    this.$root.$on('demo',function(){
        console.log('test');
    })
    this.$root.$emit('demo');
    this.$root.$off('demo');
    

    29、vue3.0与vue2.0对比

    (1)声明变更
    (2)双向绑定
    (3)观察属性
    (4)生命周期变更
    (5)vue3.0实现了dom diff和vDOM的优化
    (6)响应式原理改变
    1、vue2.0使用的是defineProperty,有两个难触屏的问题
    (1)只能做第一层属性的响应,再往深处就无法实现了
    (2)数组问题:defineProperty无法检测数组的长度变化,准确来说,是无法检测通过改变length的方法而增加的长度无法检测到
    (3)vue3.0使用的是Proxy和Reflect,直接代码整个对象
    总结:
    1、Object.defineProperty只能劫持对象的属性,而Proxy是直接代理对象,由于Object.defineProperty只能对属性进行劫持,需要遍历对象的每个属性。而Proxy可以直接代理对象。
    2、Object.defineProperty对新增属性需要手动进行Observe,由于defineProperty劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用。
    Object.defineProperty进行劫持,也是因为这个原因,使用vue给data中的数组或对象新增属性时,需要使用vm.$set才能保证新增的属性也是响应式的。
    3、Proxy支持13种拦截操作,这是defineProperty所不具有的新标准性能红利


    image.png

    4、Proxy作为新标准,长远来看,js引擎会继续优化Proxy,但getter和setter基本不会再有针对性优化。
    5、Proxy兼容性差,目前并没有一个完整支持Pxoxy所有拦截方法的Polyfill方案

    30、vue中router和route的区别

    1.$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vu构造函数得到一个router的实例对象,
    这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。

    2.route是一个跳转的路由对象,每一个路由都会有一个route对象,
    是一个局部的对象,可以获取对应的name,path,params,query等

    31、Vuex和localStorage区别

    1、最重要的区别
    (1)vuex存储在内存
    (2)localstorage则以文件的方式存储在本地
    localstorage只能存储字符串类型的数据,存储对象需要JSON的stringify和parse方法进行处理。读取内存比读取硬盘速度要快。
    (3)vuex能做到数据响应式,localstorage不能
    (4)刷新页面vuex存储的值会丢失,localstorage不会。

    相关文章

      网友评论

          本文标题:爬vue

          本文链接:https://www.haomeiwen.com/subject/eslxfltx.html