选自面试宝典--Vue部分

1、Vue的最大的优势是什么?

(1)轻量级框架,简单易学;

(2)可以进行组件化开发,数据与结构相分离,使代码量减少,从而提升开发效率,易于理解;

(3)最突出的优势是可以对数据进行双向绑定;

(4)相比传统的页面通过超链接实现页面的切换和跳转,Vue 使用路由不会刷新页面;

(5)vue 是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和 dom,这样大大加快了访问速度和提升用户体验;

(6)它的第三方UI组件库用起来节省很多开发时间,从而提升开发效率。

2、MVVM和MVC的区别是什么?哪些场景适合?

(1)MVVM(model-view-viewmodel),即模型-视图-视图模型。模型指的是后端传递的数据,视图指的是看到的页面,视图模型是MVVM模式的核心,是连接view和model的桥梁,并且它有两个方向:一个是将模型转换为视图,即将后端的数据转换为页面,实现的方式是数据绑定;二是将视图转换为模型,即将看到的页面转换为后端的数据,实现的方式为DOM事件监听。这两个方向都实现的,称之为数据的双向绑定。是基于MVC的一种架构模式,将视图和模型之间绑定自动化,减少代码量,但是会增加额外的学习成本。

(2)MVC(model-view-controller),即模型-视图-控制器。其中m和v同上,c/controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。MVC是单向通信,也就是view和model,必须通过controller来承上启下,MVC和MVVM的区别并不是vm完全取代了c,只是在MVC 的基础上增加了一层VM,只不过是弱化了c的概念,其中,模型代表数据和业务逻辑,视图代表用户界面,控制器作为中介负责调度和控制模型和视图之间的交互。MVC模式的优点是可以将应用程序的功能进行清晰的分离,提高代码的可维护性和重用性。MVC模式的缺点是需要手动编写代码实现视图和模型之间的数据交互,代码量较大,测试相对困难。

(3)区别:(区别不大,都是一种设计思想)

  • 视图与模型之间的关系不同:MVC中,视图和模型之间是通过控制器进行交互的,而在MVVM中,视图和模型是通过ViewModel进行交互的。
  • 数据绑定方式不同:MVC中,视图和模型之间的数据交互需要手动编写代码来实现,而在MVVM中,ViewModel将模型的数据绑定到视图上,实现了自动化的数据绑定。
  • 测试方式不同:在MVC中,控制器的测试相对容易,而在MVVM中,ViewModel的测试相对困难。

(4)适合场景:

MVC模式适用于简单的应用程序,比如一些新闻网站等,它能够将应用程序的功能进行清晰的分离,并提高代码的复用性和可维护性。

MVVM模式适用于需要大量操作DOM元素,比如电商网站、社交网络等,它能够减少手动编写的代码量,并提高开发效率。

3、Vue数据双向绑定的原理是什么?

vue使用数据劫持以及发布订阅的模式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发响应的监听回调。

具体步骤:

(1)需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据的变化。

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

(3)watcher订阅者是observer和compile之间通信的桥梁,相当于VM。

(4)MVVM作为数据绑定的入口,整合observer、compile和watcher三者,通过observer来监听自己的model数据变化,通过compile来解析模板指令,最终利用watcher搭起observer和compile之间的通信桥梁,达到数据变化->视图更新;视图交互变化->数据model变更的双向绑定效果。

4、Object.defineProperty和Proxy的区别?

(1)proxy可以直接监听对象而不是属性;

(2)proxy可以直接监听数组的变化【.数组的某些方法(push、unshift和splice)Object.defineProperty监听不到,Proxy可以监听到】

(3)proxy有多达13种拦截方法;

(4)proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;【对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到,需要借助$set方法】

(5)proxy在ie浏览器存在兼容性问题。

5、Vue生命周期总共分为几个阶段?

vue实例从创建到销毁的过程,也就是vue生命周期。也就是从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程,我们称之为Vue的生命周期。

【beforeCreate(创建前)、created(创建后)、beforeMount(载入前)、mounted(载入后)、beforeUpdate(更新前)、updated(更新后)、beforeDestroy(销毁前)、destroyed(销毁后)】

(1)beforeCreate--在实例初始化之后,数据观测(data observer)和event watcher事件配置之前被调用。

(2)created--在实例创建完成后被立即调用,同时,已经完成以下配置:数据观测(data observer)、属性和方法的运算,watch/event事件回调。但是,挂载阶段还没有开始,$el属性目前不可见。

(3)beforeMount--在挂载开始之前被调用:相关的render函数首次被调用。

(4)mounted--mounted是平时我们使用最多的函数了,一般我们的异步请求都写在这里。在这个阶段,数据和DOM都已被渲染出来。

(5)beforeUpdate--在这一阶段,vue遵循数据驱动DOM的原则;beforeUpdate函数在数据更新后虽然没立即更新数据,但是DOM中的数据会改变,这是Vue双向数据绑定的作用。

(6)updated--由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。

(7)activated--keep-alive组件激活时调用,该钩子在服务器端渲染期间不被调用。

(8)deactived--keep-alive组件停用时调用,该钩子在服务器端渲染期间不被调用。

(9)beforeDestroy--实例销毁前调用,在这一步,实例仍然完全可以用,该钩子在服务器端渲染期间不被调用。

(10)destroyed--vue实例销毁后使用,调用后,vue实例指示的所有东西都会被解除绑定,所有的事件监听器都会被移除,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用。

(11)errorCaptured--当捕获一个来自子孙组件的错误时被调用,此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回false以阻止该错误继续向上传播。

6、第一次加载页面时会触发哪几个钩子函数?

beforeCreate、created、beforeMount、mounted

7、封装Vue组件的过程?

(1)分析需求:确定业务需求,把页面中可以复用的结构,样式以及功能,单独抽离成一个文件,实现复用。(把页面抽象成多个相对独立的模块,可以提升整个项目的开发效率)

(2)具体步骤:

  • 使用Vue.component方法注册组件,子组件需要数据,可以在props中接受定义,而子组件修改好数据后,想把数据传递给父组件。可以采用$emit方法向外抛数据。
  • 如果需要给组件传入模板,则定义为插槽slot。
  • 如果需要父组件主动调用子组件的方法,可以在methods选项中开放方法。

8、Vue组件如何进行传值的?

(1)父组件向子组件传数据

父组件内设置要传的数据,在父组件中引用的子组件上绑定一个自定义属性并把数据绑定在自定义属性上,在子组件添加参数props接收即可。

(2)子组件向父组件传数据

子组件通过vue实例方法$emit进行处罚并且可以携带参数,父组件监听使用@(v-on)进行监听,然后进行方法处理。

(3)非父子组件之间传数据

  • 引入第三方new Vue定义为eventBus
  • 在组件中created中订阅eventBus.$on(‘自定义事件名’,methods中的方法名)
  • 在另一个兄弟组件中的methods中写函数,在函数中发布eventBus订阅的方法eventBus.$emit(‘自定义事件名’)
  • 在组件的template中绑定事件(比如click)

9、组件中写name选项有什么作用?

(1)项目中使用keep-alive时,可以搭配组件name进行缓存过滤;

(2)DOM做递归组件时需要调用自身name;

(3)vue-devtools调试工具里显示的组件名称是由vue组件name决定的。

10、vue组件data为什么必须是函数?

(1)因为Vue组件可以同时存在多个实例,如果直接使用对象形式的data选项,那么所有的实例将会共享同一个data对象,这样就会造成数据互相干扰的问题,即防止多个组件实例对象之间共用一个data,产生数据污染;

(2)采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象。当将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。

11、讲一下组件的命名规范?

(1)使用链式命名,即my-component,例如<my-component></my-component>

(2)使用大驼峰命名MyComponent,例如<MyComponent></MyComponent>。【在非字符串模板中最好使用大驼峰命名规则,因为要遵循w3c规范中的自定义组件名(字母全小写且必须包含一个连字符),避免和当前以及未来的HTML元素相冲突】

12、如何在组件中监听路由参数的变化?

有两种方法可以监听路由参数的变化,但是只能用在包含<router-view/>的组件内。

(1)watch:{

'$route'(to,from){

//在此处监听

        }

}

(2)beforeRouteUpdate(to,from,next){

//在此处监听

}

13、怎么捕获Vue组件的错误信息?

(1)使用errorCaptured这个组件内部钩子,当捕获一个来自子孙组件的错误时被调用,接收error、vm、info三个参数,return false后可以阻止错误继续向上抛出。

(2)使用errorHandler这个全局钩子,使用Vue.config.errorHandler配置,接收参数与errorCaptured一致,2.6后可以捕捉v-on与promise链的错误,可用于统一错误处理与错误兜底。

14、Vue组件里的定时器怎么销毁?

(1)如果有很多个定时器,可以在data选项中创建一个对象timer,给每个定时器去个名字一一映射在对象timer中,在beforeDestroy构造函数中for(let k in this.timer){clearInterval(k)}。

(2)如果只有单个定时器,可以这样做。const timer=setInterval(()=>{},5000);this.$once(‘hook:beforeDestroy’,()=>{clearInterval(timer);})

15、Vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?

(1)在components目录新建你的组件文件(indexPage.Vue),script一定要export default{};

(2)在需要用的页面(组件)中导入:import indexPage from '@/components/indexPage.Vue';

(3)注入到Vue的子组件的components属性上面,components:{indexPage}

(4)在template视图view中使用。【注意:用indexPage命名,使用的时候则是index-page】

16、Vue中slot的使用方式,以及slot作用域插槽的用法?

使用方式:当组件当做标签进行使用的时候,用slot可以用来接收组件标签包裹的内容,当给slot标签添加name属性的时候,可以调换相应的位置

插槽作用域:作用域插槽其实就是带数据的插槽,父组件接收来自子组件的slot标签上通过v-bind绑定进而传递过来的数据,父组件通过scope来进行接受子组件传递过来的数据。

17、Vue该如何实现组件缓存?

在面向组件化开发过程中,我们会把整个项目拆分成很多业务组件,然后按照合理的方式组织起来,那么自然会存在组件之间切换的问题,Vue有个动态组件的概念,它能够帮助开发者更好的实现组件之间的切换,但是在面对需求比较频繁的变化,去要切换组件时,动态组件在切换的过程中,组件的实例都是重新创建的,而我们需要保留组件的状态,为了解决这个问题,需要使用到Vue中内置组件<keep-alive>,<keep-alive></keep-alive>在包裹动态组件的时候,会缓存不活动的组件实例,主要用于保留组件状态或者避免重新渲染。

【比如:有一个列表和详情,那么用户就会经常执行打开详情-->返回列表-->打开详情......这样的列表和详情都是使用频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。】

18、跟keep-alive有关的生命周期是哪些?

在开发Vue项目的时候,大部分组件没必要多次渲染的,所以Vue提供了一个内置组件keep-alive来缓存组件内部状态,避免重新渲染。

在被keep-alive包含的组件中,会多出两个生命周期钩子函数--activated和deactivated;

activted:在组件第一次渲染时会被调用,之后在每次缓存组件时被激活时调用。

activated钩子调用时机:第一次进入缓存路由/组件,在mounted后面,beforeRouteEnter守卫传给next的回调函数之前调用,并且给因为组件被缓存了,再次进入缓存路由、组件时,不会触发这些钩子函数,beforeCreate created ,beforeMount mounted都不会触发;

deactivated:组件被停用时(离开路由时)调用。

deactivated调用时机:使用keep-alive就不会调用beforeDestroy(组件销毁前钩子)和destroyed(组件销毁),因为组件没有被销毁,而是被缓存起来了,这个钩子可以被看作是beforeDestroy的替代,如果你缓存了组件,要在组件销毁的时候做一些事情,可以防在这个钩子里,组件内的离开当前路由钩子beforeRouterLeave=>路由前置守卫beforeEach=>全局后置钩子afterEach=>deactivated离开缓存组件=>activated进入缓存组件(如果你进入的也是缓存路由)

19、Vue常用的修饰符有哪些?

.prevent:提交事件不再重载页面;

.stop:阻止单击事件冒泡;

.self:当事件发生在该元素本身而不是子元素的时候会触发;

.capture:事件侦听,事件发生时会调用。

20、Vue常用指令有哪些?并且说明其作用?

(1)v-model:多用于表单元素实现双向数据绑定(同angular中的ng-model);

(2)v-for:格式--相当于【字段名 in/of 数组 json】循环数组或json(同angular中的ng-repeat),需要注意从vue2开始取消了$index;

(3)v-show:显示内容(同angular中的ng-show);

(4)v-hide:隐藏内容(同angular中的ng-hide);

(5)v-if:显示与隐藏(dom元素的删除添加,同angular中的ng-if默认值为false);

(6)v-else-if:必须与v-if连用;

(7)v-else:同上;

(8)v-bind:动态绑定 作用:及时对页面的数据进行更改;

(9)v-on:click  给标签绑定函数,可以缩写为@;

(10)v-text:解析文本;

(11)v-html:解析html标签;

(12)v-bind:class 三种绑定方法 --对象型‘{red:isred}’

                                                         --三元型‘isred?red:blue’

                                                         --数组型‘[{red:isred},{blue:isblue}]’

(13)v-once:进入页面时,只渲染一次,不在进行渲染;

(14)v-cloak:防止闪烁;

(15)v-pre:把标签内部的元素原位输出。

21、自定义指令(v-check、v-focus)的方法有哪些?有哪些钩子函数?还有哪些钩子函数参数?

全局定义指令:在Vue对象的directive方法里面有两个参数,一个是指令名称,另一个是函数,组件内定义指令:directives;

钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新);

钩子函数参数:el、binding。

22、v-show和v-if指令的共同点和不同点?

共同点:v-show和v-if都能控制元素的显示隐藏;

不同点:

(1)实现的本质不同:v-show的本质是通过设置css中的display为none,从而控制隐藏;而v-if则是动态的向DOM树中添加或者删除DOM元素;

(2)编译的不同:v-show就是在控制css;而v-if切换有一个局部编译、卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;

(3)编译的条件不同:v-show都会编译,初始值为false,只是将display设置为none,但它也编译了;而v-if如果初始值为false,就不会编译了;

(4)性能的比较:v-show只编译一次,后面都是控制css,而v-if不停的销毁和创建,所以v-show性能更好一点。

【总结:如果要频繁切换某个节点时,使用v-show(无论false还是true初始都会渲染,此后通过css来控制显示隐藏,因此切换开销比较小,初始开销比较大),如果不需要频繁切换某节点时,使用v-if(因为懒加载,初始为false时,不会渲染,但是它是通过添加和删除dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销较大)】

23、为什么要避免v-if和v-for用在一起?

当vue处理指令的时候,v-for比v-if具有更高的优先级,通过v-if移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在v-if为否的时候运算v-for。

24、watch、methods和computed的区别?

基本说明:

(1)computed:计算属性将被混入到Vue实例中,所有getter和setter的this上下文自动地绑定为Vue实例。

(2)methods:将被混入到vue实例中,可以直接通过VM实例访问到这些方法,或者在指令表达式中使用。方法中的this自动绑定为Vue实例。

(3)watch:观察和响应vue实例上的数据变动,一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象,vue实例将会在实例化时调用$watch(),遍历watch对象的每一个属性。

三者的加载顺序:

(1)computed是在HTML DOM加载后马上执行,比如赋值;

(2)methods则必须有一定的触发条件才能执行,比如点击事件;

(3)watch用于观察Vue实例上的数据变动。

默认加载的时候:先是computed,再是watch,不执行methods。

触发某个事件后:先是computed再是methods接着是watch;其中computed计算属性是基于它们的依赖进行缓存的。

【总结:computed只会在它的相关依赖发送改变时才会重新求值,当有一个性能开销比较大的计算属性A,它需要遍历一个极大的数组和做大量的计算,然后我们可能有其他的计算属性依赖于A,这时候,我们就需要缓存,每次确实需要重新加载,不需要缓存时用methods。】

25、怎么在watch监听开始之后立即被调用?

在选项参数中指定immediate:true将立即以表达式的当前值触发回调。

26、watch怎么深度监听对象变化?

直接写一个监听函数,当每次监听到cityName值发生变化时,执行函数,也可以在所监听的数据后面直接加字符串形式的方法名:watch:{ cityName:‘nameChange’}

27、computed中的属性名和data中的属性名可以相同吗?

不能,因为不管是computed属性名还是data数据名还是props数据名都会被挂载在vm实例上,因此这三个都不能同名。

28、什么是vue计算属性?

因为在模板中放入太多逻辑会使得模板过重并且难以维护,所以在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。

好处:使得数据处理结构清晰;

特点:

(1)依赖于数据,数据更新,处理结构自动更新;

(2)计算属性内部this指向vm实例;

(3)在template调用时,直接写计算属性名就行;

(4)常用的是getter方法,获取数据,也可以使用set方法改变数据;

(5)相较于methods,不管数据会不会变化,methods都会重新计算,但是依赖数据不变的时候,computed从缓存中获取,不会重新计算。

29、vue中key值的作用是什么?

为了高效的更新虚拟DOM。

当vue用v-for正在更新已渲染过的元素列表时,它默认使用“就地复用”策略,如果数据项的顺序被改变,vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已经被渲染过的每个元素。

30、vue-loader是什么?使用它的用途有哪些?

vue-loader 本质上是一个 webpack 的 loader它可以解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理。

其中loader 用于对模块的源代码进行转换。它可以使你在 import 或"加载"模块时预处理文件。简单点说就是它可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件。

用途:降级----js可以写es6,style样式可以写scss或less、template可以加jade等

31、vue中怎么自定义过滤器?

在vue中,过滤器可以被用在两个地方:双花括号插值和v-bind表达式。而且过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示。

可以用全局方法vue.filter()注册一个自定义过滤器,它接收两个参数:过滤器ID和过滤器函数。过滤器函数以值为参数,返回转换后的值。过滤器同样接收全局和局部注册。

//全局注册
Vue.filter('capitalize', function(value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
 
var app = new Vue({
  el: '#app',
  data: {
    message: 'hello world'
  }
})

<div id="app">
  <p>{{ message | capitalize }}</p>
</div>

//局部注册
<div id="app">
  <p>{{ message | uppercase }}</p>
</div>
 
<script>
  var app = new Vue({
    el: '#app',
    data: {
      message: 'hello world'
    },
    filters: {
      uppercase: function(value) {
        if (!value) return ''
        value = value.toString()
        return value.toUpperCase()
      }
    }
  })
</script>

32、你是怎么认识vuex的?

vuex可以理解为是一种开发模式或者框架。比如php有thinkphp,java有spring等,通过状态(数据源)集中管理驱动组件的变化(好比spring的ioc容器对bean进行集中管理)

(1)应用级的状态集中在store中;

(2)改变状态的方式是提交mutations,这里必须是同步的;

(3)异步逻辑应该封装在action中。

33、vuex的5个核心属性是什么?

分别是state、getter、mutation、action、module

(1)state,即单一状态树,只有在state里面定义了我们所需要管理的数组、对象、字符串等等,在vue.js的组件中才能获取你定义的这个对象的状态。

(2)getter,即类似vue.js的计算属性,当我们需要从store的state中派生出一些状态,那么我们就需要使用getter,getter会接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中需要派生状态的值)发生改变的时候才会被重新计算。

(3)mutation,即更改store中state状态的唯一办法就是提交mutation,每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。

(4)action,即可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。在页面中如果我们要调用这个action,则需要执行的是store.dispatch。

(5)module,即只是解决了当state中很复杂的时候,module可以将store分割成模块,每个模块中拥有自己的state、mutation、action和getter。

34、vuex的出现解决了什么问题?

(1)多个组件依赖同一个状态时,对于多层嵌套的组件的传参将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。

(2)来自不同组件的行为需要变更同一个状态。以往采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。

35、简述vuex的数据传递过程?

当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法。

actions里面的每个方法都会有一个commit方法,当方法执行的时候会通过commit来触发mutations里面的方法进行数据的修改。

mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改。

当数据修改完毕后,会传导给页面。页面的数据从而发生改变。

36、vuex的mutation和action之间的区别是什么?

(1)流程顺序

“相应视图”-->“修改state”拆分成两个部分:视图触发action,action再触发mutation。

(2)角色定位

基于流程顺序,这俩扮演了不同的角色:

mutation--专注修改state,理论上是修改state的唯一途径。

action--业务代码,异步请求。

(3)限制

角色不同,所以有不同的限制:

mutation:必须同步执行。

action:可以异步,但是不能直接操作state。

37、vue-router是干什么的?原理是什么?

vue-router是vue.js官方的路由插件,和vue.js是深度集成的,适用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。

路由模块的本质,就是建立起url和页面直接的映射关系。

“更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:

利用URL中的hash(‘#’);

利用history interface在h5中新增的方法。

38、路由之间是怎么跳转的?有哪些方式?

(1)声明式导航:<router-link to="需要跳转页面的路径">

(2)编程式导航:

路由跳转--this.$router.push()跳转到指定的url,并且在history中添加记录,点击回退返回到上一个页面。

路由替换--this.$router.replace()跳转到指定的url,并且在history中不会添加记录,点击回退返回到上上个页面。

·this.$router.go(n)向前或者后跳转n个页面,n可以是正数也可以是负数。

路由后退--this.$router.back()。

路由前进--this.$router.forward()。

39、vue-router怎么配置路由?

在vue中配置路由分为5个步骤,分别是:

(1)安装

npm install --save Vue-Router

(2)引用

import VueRouter from 'Vue-Router'

(3)配置路由文件

const router=new VueRouter({

routes:[

{path:‘/hello’,component:HelloWorld}

]

})

(4)视图加载位置

默认App.vue文件中加<router-view></router-view>

(5)跳转导航(渲染出来的是a标签)

<router-link to="/hello">helloworld</router-link>

40、vue-router有哪几种路由守卫?

(1)全局守卫:beforeEach;

(2)后置守卫:afterEach;

(3)全局解析守卫:beforeResolve;

(4)路由独享守卫:beforeEnter。

41、vue-router的钩子函数有哪些?

vue-router中的钩子函数主要分为3类:

(1)全局钩子函数要包含beforeEach

(2)单独路由独享组件:beforeEnter;

(3)组件内钩子:beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave。

42、路由传值的方式有哪几种?

(1)router-link路由导航

父组件: 使用<router-link to = "/跳转路径/传入的参数"></router-link>

例如:<router-link to="/a/123">routerlink传参</router-link>

子组件: this.$route.params.num接收父组件传递过来的参数

(2)调用$router.push实现路由传参

父组件: 绑定点击事件,编写跳转代码

<button @click="deliverParams(123)">push传参</button>

  methods: {

    deliverParams (id) {

      this.$router.push({

        path: `/d/${id}`

      })

    }

  }

子组件: this.$route.params.id接收父组件传递过来的参数

mounted () {

  this.id = this.$route.params.id

}

(3)通过路由属性中的name匹配路由,再根据params传递参数

父组件: 匹配路由配置好的属性名

<button @click="deliverByName()">params传参</button>

    deliverByName () {

      this.$router.push({

        name: 'B',

        params: {

          sometext: '一只羊出没'

        }

      })

    }

子组件:

<template>

  <div id="b">

    This is page B!

    <p>传入参数:{{this.$route.params.sometext}}</p>

  </div>

</template>

(4)通过query来传递参数

父组件:

<button @click="deliverQuery()">query传参</button>

    deliverQuery () {

      this.$router.push({

        path: '/c',

        query: {

          sometext: '这是小羊同学'

        }

      })

    }

子组件:

<template>

  <div id="C">

    This is page C!

    <p>这是父组件传入的数据: {{this.$route.query.sometext}}</p>

  </div>

</template>

43、怎么定义vue-router的动态路由?怎么获取传过来的动态参数?

动态路由就是把某种模式下匹配到的所有路由,全部映射到同个组件。其实本质就是通过url进行传参。

例如:有一个商品item的组件,我们需要让不同的商品id都映射到这个组件中,此时就需要用到动态路由了。

动态路径参数,使用“冒号”开头,一个路径参数,使用冒号标记,当匹配到一个路由时,参数会被设置到this.$router.params中,并且可以在每个组件中使用。

【通过动态路由传参,在路由中设置了多段路径参数后,对应的值分别都会设置到$router.query和$router.params中】

44、query和params之间的区别是什么?

//query
this.$router.push({path;“地址”,query:{id:“123”JJ); //这是传递参数
this.$route.query.id; 这是接受参数
//params
this.$router.push({name:“地址”,params:{id:“123”]});//这是传递参数
this.$route.params.id; //这是接受参数

区别:

(1)首先就是写法的不同,query的写法是 用 path 来编写传参地址,而 params 的写法是用 name 来编写传参地址;

(2)接收方法不同, 一个用 query 来接收, 一个用 params 接收 ,总结就是谁发的 谁去接收;

(3)query 在刷新页面的时候参数不会消失,而 params 刷新页面的时候会参数消失,可以考虑本地存储解决;

(4)query 传的参数都是显示在url 地址栏当中,而 params 传参不会显示在地址栏。

45、$route和$router的区别是什么?

路由跳转使用 “router”;获取参数使用“route”

$route是“路由信息对象”,包括path、params、hash、query、name等路由信息参数。每一个路由都会有一个$route对象,是一个局部的对象。

$router是VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。

//$route
主要的属性有:
this.$route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如/home/ews
 
this.$route.params 对象,包含路由中的动态片段和全匹配片段的键值对,不会拼接到路由的url后面
 
this.$route.query 对象,包含路由中查询参数的键值对。会拼接到路由url后面
 
this.$route.router 路由规则所属的路由器
 
this.$route.name 当前路由的名字,如果没有使用具体路径,则名字为空
//$router
//常规方法
this.$router.push("/login");
//使用对象的形式 不带参数
this.$router.push({ path:"/login" });
//使用对象的形式,参数为地址栏上的参数
this.$router.push({ path:"/login",query:{username:"jack"} }); 
使用对象的形式 ,参数为params 不会显示在地址栏
this.$router.push({ name:'user' , params: {id:123} });

46、vue的路由实现模式:hash模式和history模式?

(1)hash模式:

在浏览器中符号“#”,“#”以及“#”后面的字符称之为hash;

用window.location.hash读取。

特点:hash虽然在URL中,但不被包括在HTTP请求中,用来指导浏览器动作,对服务器安全无用,hash不会重新加载页面。

(2)history模式:

采用html5的新特性,且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。

【区别:

1.hash模式地址栏中带#,history不带;

2.hash模式兼容性比history好;

3.由于hash值不会包含在http请求中(即hash值不会带给服务器),所以不会刷新404;但history部署上线后刷新会404(因为服务器把地址栏中的值当作服务器的接口了)】

47、请说出路由配置项常用的属性及作用?

路由配置参数:   

path:跳转路径;

component:路径相对于的组件;

name:命名路由;

children:子路由的配置参数(路由嵌套);

props:路由解耦;

redirect:重定向路由。

48、vue怎么实现跨域?

首先,跨域是指浏览器不允许当前页面的所在的源去请求另一个源的数据。源指的是协议、端口、域名。只要这三个有一个不同的就是跨域。

怎么实现跨域?

(1)使用 vue-cli 脚手架搭建项目时 proxyTable 解决跨域问题

//打开 config/index.js,在 proxyTable 中添写如下代码:
proxyTable: {
'/api': { //使用"/api"来代替"http://f.apiplus.c"
target: 'http://f.apiplus.cn', //源地址
changeOrigin: true, //改变源
pathRewrite: {
'^/api': 'http://f.apiplus.cn' //路径重写
}

(2)使用 CORS(跨域资源共享)

//前端设置:vue 设置 axios 允许跨域携带 cookie(默认是不带 cookie) 
axios.defaults.withCredentials = true;
//后端设置:跨域请求后的响应头中需要设置
Access-Control-Allow-Origin 为发起请求的主机地址
Access-Control-Allow-Credentials,当它被设置为 true 时,允许跨域 带 cookie,
但此时 Access-Control- Allow-Origin 不能为通配符*
Access-Control-Allow-Headers,设置跨域请求允许的请求头
Access-Control-Allow-Methods,设置跨域请求允许的请求方

49、vue中动画如何实现?

哪个元素需要动画就给那个元素加transition标签,

(1)进入时class的类型可以分为以下几种:

<name>-enter、<name>-enter-active、<name>-enter-to;

(2)离开时class的类型可以分为以下几种:

<name>-leave、<name>-leave-active、<name>-leave-to;

如果需要一组元素发生动画需要用标签<transition-group></transition-group>

50、你对vue的template编译的理解?

简而言之,就是先转换为AST树,再得到的render函数返回VNode(vue的虚拟DOM节点)。

AST即abstract syntax tree也就是源代码的抽象语法结构的树状表现形式;

VNode是vue的虚拟DOM节点,里面有(标签名、子节点、文本等)。

51、vue渲染模板时怎么保留模板中的html注释呢?

在组件中将comments选项设置为true

<template comments>...</template>

52、vue如何去除URL中的#?

vue-router默认使用是hash模式,所以在路由加载的时候,项目中的URL会自带“#”,如果不想使用“#”,可以使用vue-router的另一种模式--history:new Router({mode:‘history’,routes:[ ] })

【注意:因为我们启用history模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现“404”的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果URL匹配不到任何静态资源,则应该返回同一个“index.html”页面。】

53、在vue中使用插件的步骤?

采用ES6的import ... from ...语法或者CommonJS的require()方法引入插件。

使用全局方法 Vue.use(plugin)使用插件,可以传入一个选项对象Vue.use(MyPlugin,{someOption:true})。

54、vue项目优化的解决方案都有哪些?

(1)使用mini-css-extract-plugin插件抽离css;

(2)配置optimization把公共的js代码抽离出来;

(3)通过webpack处理文件压缩;

(4)不打包框架、库文件,通过cdn的方式引入;

(5)小图片使用base64;

(6)配置项目文件懒加载;

(7)UI库配置按需加载;

(8)开启Gzip压缩。

55、使用vue的时候加载造成页面卡顿,该如何解决?

Vue-Router解决首次加载缓慢的问题,懒加载简单来说就是按需加载。

【像vue这单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,即使做了loading也是不利于用户体验,而运用懒加载,则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时】

【用法:在配置路由时使用:component:resolve=>require([“@components/路
由的路径”],resolve)。 就是用了懒加载后打完包直接运行那个 index.html 会报错,报文
件引用错误其实是打包时候路径配置有点问 题,找到 build 下面的
webpack.prod.conf.js 添加 publicPath:“./”,】

56、请说出vue-cli项目中src目录每个文件夹和文件的用法?

(1)assets文件夹是放静态资源;

(2)components是放组件;

(3)router是定义路由相关的配置;

(4)view视图

(5)app.vue是一个应用主组件;

(6)main.js是入口文件。

57、你知道style上加scoped属性的原理吗?

加上scoped是为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,局部有效。(实现了样式的私有化)

实现原理:主要是通过PostCSS转译实现,给节点新增自定义属性,然后css根据属性选择器添加样式。

58、怎样理解vue的单向数据流?

数据从父级组件传递给子组件,只能单向绑定;子组件内部不能直接修改从父级传递过来的数据。

Vue的单向数据流指的是,数据在父组件中被定义和更新,然后通过props的形式传递给子组件,子组件可以读取这些props,但不能直接修改它们。如果子组件需要修改这些数据,需要通过$emit方法将事件发送给父组件,由父组件来更新数据。

【这种单向数据流的好处是,可以更好地维护数据的可追溯性和可预测性,减少了代码的复杂度,方便开发和维护。】

<!-- 父组件 -->

<template>
  <div>
    <h1>{{ title }}</h1>
    <child-component :count="count" @increment="incrementCount"></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  data() {
    return {
      title: 'Hello, Vue!',
      count: 0
    }
  },
  components: {
    ChildComponent
  },
  methods: {
    incrementCount() {
      this.count++
    }
  }
}
</script>
<!-- 子组件 -->
<template>
  <div>
    <h2>Count: {{ count }}</h2>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
export default {
  props: {
    count: {
      type: Number,
      required: true
    }
  },
  methods: {
    increment() {
      this.$emit('increment')
    }
  }
}
</script>

59、VNode是什么?什么是虚拟DOM?

(1)VNode是什么?

        VNode是javascript对象,VNode表示Virtual DOM(虚拟DOM)中的虚拟节点,用Javascript对象来描述真实的DOM把DOM标签属性,内容都变为对象属性

(2)VNode的优点?

        兼容性强,不受执行环境的影响

        减少操作DOM,提高页面性能

(3)什么是虚拟DOM?

        虚拟 dom 是相对于浏览器所渲染出来的真实 dom而言的 就是一个普通的 JavaScript 对象,目的是为了进行最小化地DOM操作。

         虚拟 DOM 主要做了两件事:

  • 提供与真实 DOM 节点所对应的虚拟节点 vnode

  • 将新的虚拟节点和旧的虚拟节点进行对比,然后更新页面

        为什么不使用真实DOM?

        创建真实DOM成本比较高,而如果用js对象来描述一个dom节点,成本比较低,另外我们在频繁操作dom是一种性能开销比较大。所以用虚拟dom来描述真实dom。

60、vue中如何实现一个虚拟DOM?

首先要建立一个VNode的类,DOM元素上的所有属性在VNode类实例化出来的对象上都存在对应的属性。

将VNode类实例化出来的对象进行分类。

然后通过编译将模板转成渲染函数render,执行渲染函数render,在其中创建不同类型的VNode类,最后整合就可以得到一个虚拟DOM。

最后通过patch将VNode和oldVNode进行比较后,生成真实的DOM。

61、vue中操作data中数组的方法哪些可以触发视图更新,哪些不可以,不可以的话有什么解决方法?

可以触发视图更新的方法:

push()、pop()、shift()、unshift()、splice()、sort()、sort()、reverse()这些方法会改变被操作的数组;

filter()、concat()、slice()这些方法不会改变被操作的数组,返回一个新的数组;

不可以触发视图更新:

利用索引直接设置一个数组项,例如:this.array[index]=newValue;

直接修改数组的长度,例如:this.array.length=newLength.

解决方法:

(1)可以用this.$set(this.array,index,newValue)或者this.array.splice(index,1,newValue)

(2)可以用this.array.splice(newLength)

62、vue中怎么重置data?

(1)使用Object.assign()方法,可以实现重置data中的数据。

基本定义:Object.assign()方法用于将所有的可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

用法:Object.assign(target,...sources),第一个参数是目标对象,第二个参数是源对象,就是将源对象属性复制到目标对象,返回目标对象。

<template>
  <div>
    <button @click="resetData">重置</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "",
      age: 0,
      gender: "",
    };
  },
  methods: {
    resetData() {
      let initialData = {
        name: "",
        age: 0,
        gender: "",
      };
      Object.assign(this.$data, initialData);
    },
  },
};
</script>

(2)利用v-bind和computed

首先在Vue组件内定义一个初始值对象originalData,之后利用v-bind指令绑定到各个表单元素上。最后,我们可以利用computed计算属性将data数据与原始数据进行比较,如果不同,就将data数据重置为初始状态。

<template>
  <div>
    <input v-bind:value="name" @input="name = $event.target.value" />
    <input v-bind:value="age" @input="age = $event.target.value" />
    <input v-bind:value="gender" @input="gender = $event.target.value" />
    <button @click="resetData">重置</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "",
      age: 0,
      gender: "",
    };
  },
  computed: {
    originalData() {
      return {
        name: "",
        age: 0,
        gender: "",
      };
    },
  },
  methods: {
    resetData() {
      if (JSON.stringify(this.$data) !== JSON.stringify(this.originalData)) {
        this.$data = Object.assign({}, this.originalData);
      }
    },
  },
};
</script>

(3)使用$refs指令

在Vue组件内使用ref来指定表单元素的名称,之后我们可以利用$refs指令来重置这些元素的值:

<template>
  <div>
    <input ref="name" v-model="name" />
    <input ref="age" v-model="age" />
    <input ref="gender" v-model="gender" />
    <button @click="resetData">重置</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "",
      age: 0,
      gender: "",
    };
  },
  methods: {
    resetData() {
      Object.keys(this.$refs).forEach(key => {
        this.$refs[key].value = "";
      });
    },
  },
};
</script>

63、如何对vue首屏加载实现优化?

(1)将不常改变的库放到index.html中,通过cdn引入;

(2)vue路由的懒加载;

(3)不生成map文件;

(4)vue组件尽量不要全局引入;

(5)使用更轻量级的工具库;

(6)开启gzip压缩;

(7)首页单独做服务端渲染。

64、vue的$nextTick的原理是什么?

(1)为什么需要nextTick?

因为vue是异步修改DOM的并且不鼓励开发者直接接触DOM,但是有的时候业务需要必须对数据更改--刷新后的DOM做相应的处理,这时候就可以使用vue.nextTick(callback)这个api了。

(2)理解前的准备--什么是宏任务、什么是微任务?

常见的宏任务有:script、setTimeout、setInterval、I/O、UI rendering;

常见的微任务有:process、nextTick(node.js)、promise.then()、mutationObserver。

(3)理解原理是什么?

$nextTick 是vue中的异步更新,vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式。

65、在vue实例中编写生命周期hook或者其他option/propertie时,为什么不使用箭头函数?

因为箭头函数自己没有定义this上下文,而不是绑定到其父函数的上下文中。

当你在vue程序中使用箭头函数(=>)时,this关键字并不会绑定到vue实例上,因此会引发错误,所以建议使用标准函数声明。

66、is这个特性你用过吗?主要用在哪些方面?

1)动态组件
<component :is="componentName"></component>, componentName 可以是在本页面已经注册的局部组件名和全局组件名,也可以是一个组件的选项对象。当控制 componentName 改变时就可以动态切换选择组件。
2)is 的用法
有些 HTML 元素,诸如 <ul>、<ol>、<table>和<select>,对于哪些元素可以出现在其内部是有严格限制的。而有些 HTML 元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。
<ul>
<card-list></card-list>
</ul>
上面的<card-list />是自定义的已声明注册组件,由于ul内无法识别
所以上面<card-list></card-list>会被作为无效的内容提升到外部,并导致最终渲染结果出错。应该这么写:
<ul>
<li is="cardList"></li>
</ul>

67、scss是什么?在vue.cli中的安装使用步骤是?有哪几大特性?

(1)scss是一种css预处理语言,是一个css的扩展,它在css语法的基础上,允许使用变量,嵌套规则,混合,导入,继承等功能,使得css更加强大和优雅,而且其完全兼容css3。

(2)在vue.cli中的使用方法:

第一步:先装 css-loader、 node-loader、 sass-loader 等包
第二步:在 build 目录找到 webpack.base.config.js,在那个 extends 属性中加一个拓展.scss
第三步:在同一个文件,配置一个 module 属性
第四步:然后在组件的 style 标签加上 lang 属性 ,例如: lang=” scss

(3)特性

可以用变量,例如( $变量名称=值);
可以用混合器,例如()
可以嵌套

68、说说你对SPA单页面的理解,它的优缺点分别是什么?

SPA(single-page application)单页web应用是一种特殊的web应用,它将所有的活动局限在一个web页面中,仅在该web页面初始化时加载相应的html、js、css。一旦页面加载完成了,SPA就不会因为用户的操作而进行页面的重新加载或跳转。取而代之的是利用JavaScript动态的变换HTML的内容,从而实现UI与用户的交互。由于避免了页面的重新加载,SPA提供了较为流畅的用户体验。得益于ajax,我们可以实现无跳转刷新;多亏了浏览器的history机制,我们用hash的变化从而可以实现推动界面的变化,从而模拟元素客户端的单页面切换效果。

优点:

(1)无刷新页面,给用户体验原生的应用感觉;

(2)节省原生(andriod和ios)app开发成本;

(3)提高发布效率,无需每次安装更新包;

(4)容易借助其他知名平台更利于营销和推广;

(5)符合web2.0的趋势。

缺点:

(1)效果和性能确实和原生有很大差距;

(2)各个浏览器的版本兼容性不一样;

(3)业务随着代码量增加而增加,不利于首屏优化;

(4)某些平台对hash有偏见,有些甚至不支持pushState;

(5)不利于搜索引擎抓取。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值