vue细节讲解

vue题库

  • 自 检
    • vue部分
      • 1、什么是vue生命周期?有什么作用?
      • 2、第一次页面加载不是 keep-alive 的第一次加载会触发哪几个钩子
      • 3-1、性能优化
      • 3-2、移动端的性能优化
      • 3-3、Vue项目性能优化
        • 3-3-1:Vue 代码层面的优化;
        • 3-3-2:webpack层面的的优化
        • 3-3-3:web层面的技术优化
    • 前端seo的优化方向
    • vue基础篇
    • 路由模块问题 — vue-router篇
    • 补充
      • 虚拟DOM的原理
      • MVVM的原理
      • 在父子组件通讯过程中,子组件的哪个生命周期函数最先获取到props数据?
      • vue单文件
      • 什么是模块化:
      • 什么是组件化:
      • vue是如何实现组件化的:
      • vue文件里面包括三部分:
      • Vue的父组件和子组件生命周期钩子函数执行顺序?
    • mvvm图示

自 检

vue部分

后台管理权限:后台管理系统
vue中如何实现后台管理系统的权限控制:vue中如何实现后台管理系统的权限控制

VUE中如何实现后台管理系统的权限控制:VUE中如何实现后台管理系统的权限控制

vue3.0:Vue3.0简单认识

简单介绍

1、什么是vue生命周期?有什么作用?

每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
vue细节讲解_第1张图片

2、第一次页面加载不是 keep-alive 的第一次加载会触发哪几个钩子

第一次页面加载时会触发beforeCreate, created, beforeMount, mounted这几个钩子

3-1、性能优化

  1. 从设计实现层面简化页面

  2. 合理设置 HTTP缓存

  3. 资源合并与压缩

  4. 合并 CSS图片,减少请求数的又一个好办法。

  5. 将外部脚本置底(将脚本内容在页面信息内容加载后再加载)

  6. 多图片网页使用图片懒加载。

  7. 当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。

  8. 在js中尽量减少闭包的使用

  9. 尽量合并css和js文件

  10. 减少对DOM的操作

  11. 在JS中避免“嵌套循环”和 “死循环”

  12. 尽可能使用事件委托(事件代理)来处理事件绑定的操作

图片的使用场景

  • 尽量使用字体图标或者SVG图标,来代替传统的PNG等格式的图片
  • jpg有损压缩格式,png是无压缩格式,所以相同图片jpg体积较小
  • jPG 适用于呈现色彩丰富的图片,在我们日常开发中,JPG 图片经常作为大的背景图、轮播图或 Banner 图出现。
  • png呈现小的 Logo、颜色简单且对比强烈的图片或背景等。
  • SVG无损、矢量图、体积小、不失真、兼容性好

jpg优点:

  1. 普遍应用于需要连续色调的图像如色彩丰富的图片
  2. 可利用可变的压缩比以控制文件大小;

jpg缺点:

  1. 不适合用来存储企业 Logo、线框类的图。因为有损压缩会导致图片模糊
  2. 图像不支持透明度处理,透明图片需要召唤 PNG 来呈现

svg 优点

  1. SVG 可被非常多的工具读取和修改(比如记事本)。
  2. SVG图形格式可以用来动态生成图形。

svg 缺点

  1. 渲染成本比较高,对于性能有影响。渲染成本比较高,对于性能有影响。

适用场景

  1. 高保真度复杂矢量文档已是并将继续是 SVG 的最佳点。它非常详细,适用于查看和打印,可以是独立的,也可以嵌入到网页中

3-2、移动端的性能优化

  1. 首屏加载和按需加载,懒加载
  2. 资源预加载
  • 预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源
  • 使用HTML标签如下
  • < img src="http://pic26.nipic.com/20121213/6168183 0044449030002.jpg" style="display:none"/>
  • 使用Image对象-如下
  • var image= new Image() image.src="http://pic26.nipic.com/20121213/6168183 004444903000 2.jpg"

懒加载和预加载的对比

  • 两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力
  1. 图片压缩处理,使用base64内嵌图片
  2. 合理缓存dom对象
  3. 使用touchstart代替click(click 300毫秒的延迟)
  4. 利用transform:translateZ(0),开启硬件GUP加速
  5. 不滥用web字体,不滥用float(布局计算消耗性能),减少font-size声明
  6. 使用viewport固定屏幕渲染,加速页面渲染内容
  7. 尽量使用事件代理,避免直接事件绑定

3-3、Vue项目性能优化

3-3-1:Vue 代码层面的优化;

1.1、v-if 和 v-show 区分使用场景

  • v-if真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
  • v-show 就简单得多, 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 display 属性进行切换。
  • v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。

1.2、computed 和 区分使用场景

  • computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值
  • watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

运用场景:

  • 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
  • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

1.3、v-for 遍历必须为 item 添加 key,且避免同时使用 v-if

(1)v-for 遍历必须为 item 添加 key

在列表数据进行遍历渲染时,需要为每一项 item 设置唯一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值对比,较快地定位到 diff

(2)v-for 遍历避免同时使用 v-if

v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候,必要情况下应该替换成 computed 属性。

1.4、图片资源懒加载

图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户体验。我们在项目中使用 Vue 的 vue-lazyload 插件:

(1)安装插件npm install vue-lazyload --save-dev

(2)在入口文件man.js 中引入并使用 然后再 vue 中直接使用Vue.use(VueLazyload)

(3)在 vue 文件中将 img 标签的 src 属性直接改为 v-lazy ,从而将图片显示方式更改为懒加载显示:< img v-lazy="/static/img/1.png">

1.5、路由懒加载在简历当中的项目面试题有更详细解释

Vue 是单页面应用,可能会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。

1.6、第三方插件的按需引入

我们在项目中经常会需要引入第三方插件,如果我们直接引入整个插件,会导致项目的体积太大,我们可以借助babel-plugin-component,然后可以只引入需要的组件,以达到减小项目体积的目的。以下为项目中引入element-ui 组件库为例:

1.7、服务端渲染 SSR or 预渲染

服务端渲染是指 Vue 在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的 html 片段直接返回给客户端这个过程就叫做服务端渲染。

(1)服务端渲染的优点:

更好的 SEO:因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;

更快的内容到达时间(首屏加载更快):SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;

(2)服务端渲染的缺点:

更多的开发条件限制:例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server运行环境;

更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源,因此如果你预料在高流量环境下使用,请准备相应的服务器负载,并明智地采用缓存策略

3-3-2:webpack层面的的优化

2.1、Webpack 对图片进行压缩

在 vue 项目中除了可以在 webpack.base.conf.jsurl-loader中设置 limit 大小来对图片处理,对小于 limit 的图片转化为 base64 格式,其余的不做操作。所以对有些较大的图片资源,在请求资源的时候,加载会很慢,我们可以用 image-webpack-loader来压缩图片:

(1)首先,安装image-webpack-loader

(2)然后,在webpack.base.conf.js中进行配置:

  loader: 'image-webpack-loader'

2.2、减少 ES6 转为 ES5 的冗余代码

Babel 插件会在将 ES6 代码转换成 ES5 代码时会注入一些辅助函数,例如下面的 ES6 代码:

Babel 会在每个输出文件中内嵌这些依赖的辅助函数代码,如果多个源代码文件都依赖这些辅助函数,那么这些辅助函数的代码将会出现很多次,造成代码冗余。为了不让这些辅助函数的代码重复出现,可以在依赖它们时通过 require(‘babel-runtime/helpers/createClass’) 的方式导入,这样就能做到只让它们出现一次。babel-plugin-transform-runtime 插件就是用来实现这个作用的,将相关辅助函数进行替换成导入语句,从而减小 babel 编译出来的代码的文件大小。

(1)首先,安装 babel-plugin-transform-runtime

(2)然后,修改 .babelrc配置文件为:

"plugins": [
    "transform-runtime"
]

2.3、提取公共代码

如果项目中没有去将每个页面的第三方库和公共模块提取出来,则项目会存在以下问题:

  • 相同的资源被重复加载,浪费用户的流量和服务器的成本。
  • 每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验。

2.4、上线前 使用webpack 的可视化工具查看

$ npm run build --report

3-3-3:web层面的技术优化

3.1、浏览器缓存

为了提高用户加载页面的速度,对静态资源进行缓存是非常必要的,根据是否需要重新向服务器发起请求来分类,将 HTTP 缓存规则分为两大类(强制缓存,对比缓存),如果对缓存机制还不是了解很清楚的,可以参考作者写的关于 HTTP 缓存的文章《深入理解HTTP缓存机制及原理》

缓存的处理步骤

1首先是当用户请求资源时,会判断是否有缓存,

2如果没有,则会向原服务器请求资源。

3如果有缓存,则会进入强缓存的范畴,判断缓存是否新鲜

4判断缓存是否过期没有过期读取304缓存过期了重新响应

3.2、CDN 的使用

浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器连接,而大部分服务器的带宽有限,如果超过限制,网页就半天反应不过来。而 CDN 可以通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且CDN 具有更好的可用性,更低的网络延迟和丢包率 。

3-3、前端SEO优化

搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排

前端seo的优化方向

1、 语义化标签,根据情况适当使用h、ul、li、等语义标签,但要注意使用的合理,防止堆砌和作弊(检测到作弊会有相应的惩罚,并且不是合理的实现方式)。

2、 使用新的语法和技术规范会让蜘蛛认为你的网站是持续维护并且技术新颖的。

3、 首页标题head中 title标签适当增加长度,通过关键词搜索量进行增加(一般不超过80个字符)且词语间要用英文“-”隔开

4、 网址后缀优化,最好不要出现动态的网址如www.xiaobaitu.com/index?type=aa,这种域名会导致该页seo受到致命打击,建议做成www.xiaobaitu.com/index/type/aa,这种网址会方便蜘蛛进行爬取。同时不建议网址过长一般最好控制在三层以内,过长的url嵌套不利于seo。

5、一些注释和无用的代码最好去掉,否则会给造成蜘蛛的误解和麻烦。

6-1、< img > 标签的 alt 属性指定了替代文本 示例:< img src=“xxx.jpg” alt=“海尔官网-双门冰箱” />建议只加alt属性。因为容易造成关键词堆砌

6-2、 < a >标签:页内链接,要加 “title” 属性加以说明,让访客和 “蜘蛛” 知道。而外部链接,链接到其他网站的,则需要加上 el=“nofollow” 属性, 告诉 “蜘蛛” 不要爬,因为一旦“蜘蛛”爬了外部链接之后,就不会再回来了。

< a href=“https://www.360.cn” title=“360安全中心” class=“logo”>< /a >

6-3、 < strong >、< em >标签 :需要强调时使用。< strong >标签在搜索引擎中能够得到高度的重视,它能突出关键词,表现重要的内容

< meta >标签优化 网页 的Title、Keyword、Description -----TKD

7、 T、< title >标题:只强调重点即可,尽量把重要的关键词放在前面,关键词不要重复出现,尽量做到每个页面的< title >标题中不要设置相同的内容。 < title >当前页面的标题< /title >

8、 K、一般在vue或者jquery的项目当中里面有index.html这个文件,的meat标签的name属性语法格式是:< Meta name=“Keywords” Content=“关键词1,关键词2,关键词3,关键词4,……”> ,各关键词间用英文逗号 搜索引擎会使用lang特性来过滤并通过用户的语言优先参照来显示搜索结果一般设置 lang=”zh-cn” 在添加一个meta标签为 Lang=“EN”

关键字不宜以统一形式重复3——6次,重复过多会产生关键字垃圾,因此还有可能会受到惩罚。

9、 D、说明:Description用来告诉搜索引擎你的网站主要内容。

用法:< Meta name=“Description” Content=“你网页的简述”>

3-4、防范 CSRF 攻击可以遵循以下几种规则:

完成 CSRF 攻击的条件:攻击

  1. 浏览登陆网站A
  2. 网站A用户验证通过,在用户客户端产生cookie
  3. 用户在没有登出A网站的情况下,访问到了危险网站B
  4. 网站B对网站A发送恶意请求
  5. 浏览器带着恶意请求之前保存的cookie访问网站A
  6. 因为带着cookie,网站A以为是用户在操作,处理了网站B的恶意请求。从而达到了模拟用户操作的目的。

防御

1、请求时附带验证信息,比如验证码或者使用token,Token验证的 CSRF 防御机制是公认最合适的方案

应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。

具体操作:用户登录时根据用户名和密码等加密生成一个 Token 值,同时写入到浏览器的 Cookie 和Hidden 中,然后根据每次的请求将 Token 和 Cookie 同时带入到服务端进行验证和判断。

8、$nextTick的使用

this.$nextTick() 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新;

比如通过this.$nextTick() 获取到的值为dom更新之后的值;

9、vue中过滤器有什么作用及详解 vue.filter

也就是说,让数据按照我们规定的一种格式输出

10、vue.js的两个核心是什么

数据驱动、组件系统

数据驱动: ViewModel,保证数据和视图的一致性。

组件系统: 应用类UI可以看作全部是由组件树构成的。

11、params和query的区别 路由传递参数的两种方式

paramsquery 都是为了传递参数

1、params:只能用name引入路由传参

2、query:则是用path引入路由传参

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

一句话该概括:Vue-router 允许我们通过不同的url来访问不同的内容、实现多视图单页面的web应用

SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载

优点:

用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;

基于上面一点,SPA 相对对服务器压力小

13-1、computed 和 watch 的区别和运用的场景?

computed:是计算属性,.computed擅长处理的场景:一个数据受多个数据影响 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;  最典型的例子: 购物车商品结算的时候

watch:watch擅长处理的场景:一个数据影响多个数据更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

当一条数据影响多条数据的时候就需要用watch 搜索数据

而和watch和computed相关的函数,会自动调用

immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。

 watch用法

 第一:一般用法watch监听数据值变化时执行

 第二:监听的数据后面写成对象形式,包含handler方法和immediate

 immediate表示在 watch 中首次绑定的时候,是否执行handler,

 值为true则表示在 watch 中声明的时候,就立即执行handler方法,

 值为false,则和一般使用 watch 一样,在数据发生变化的时候才执行handler。

 watch: {

        $route: {
            handler: function(val, oldVal) {
                if (
                || this.$route.name === '3165b5457892431dbb130fb9a235b939'
                || this.$route.name === '3431a76790ba41e29c106eccf71effef'
                || this.$route.name === '4eb730925a6a420994cab4ab4f523917')
                 {
                    this.displaySearch = false
                } else {
                    this.displaySearch = true
                }
            },

           //1、deep为了发现对象内部值的变化,可以在选项参数中指定 deep: true            
            deep: true,

          //在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调 
          //如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性         
            immediate: true
        }
    },
    

13-2、watch的深度遍历和立即调用功能

​ watch 来监听数据变化的时候通常只使用过其中的 handler 回调,其实其还有两个参数,便是
1、deep 设置为 true 用于监听对象内部值的变化。
2、immediate 设置为 true 将立即以表达式的当前值触发回调

<template>
    <button @click="obj.a = 2">修改</button>
</template>

<script>
export default {
    data() {
        return {
            obj: {  a: 1, }
                }
            },
    watch: {

        obj: {
            handler: function(newVal, oldVal) {
                console.log(newVal); 
            },
            deep: true,
            immediate: true}
         }
   }

</script>

以上代码我们修改了 obj 对象中 a 属性的值,我们可以触发其 watch 中的 handler 回调输出新的对象,而如果不加 deep: true,我们只能监听 obj 的改变,并不会触发回调。同时我们也添加了 immediate: true 配置,其会立即以 obj 的当前值触发回调

在 Vue 源码中,主要使用了 Object.defineProperty (obj, key, option) 方法来实现数据的监听,同时其也是 Vue 数据双向绑定的关键方法之一。把对象传过来的的双向绑定原理做下解释

13-2、Vue Computed 原理

computed的基本特性是:

1、当data数据变更时,computed会更新

2、当computed中没有引入的数据更新时,computed不会去重新计算,大幅度节省计算量

  1. data 属性初始化 getter setter

  2. computed 计算属性初始化,提供的函数将用作属性 vm.reversedMessage 的 getter

  3. 当首次获取 reversedMessage 计算属性的值时,Dep 开始依赖收集

  4. 在执行 message getter 方法时,如果 Dep 处于依赖收集状态,则判定 message 为 reversedMessage 的依赖,并建立依赖关系

  5. 当 message 发生变化时,根据依赖关系,触发 reverseMessage 的重新计算

到此,整个 Computed 的工作流程就理清楚了。

14、单页面应用缺点?

单页面应用程序将所有的活动 局限于一个web页面中。改页面仅仅在页面初始化时加载相应的html、javascript 和 css,SPA 不会因为用户的操作而进行页页面重新加载或者跳转。反而取而代之的javascript取代html内容从而实现了ui于用户的交互

单页面应用程序(SPA)的优缺点

优点:

1、良好的交互体验

2、良好的前后端工作分离模式

3、减轻服务器压力、

缺点:

1、首屏加载慢;

2、不利于SEO;

3、不适合开发大型项目(大型项目中会涉及到大量的dom节点操作)

15、什么是MVVM,和MVC有什么区别,原理是什么?

  • mvc的界面和逻辑关联紧密,数据直接从数据库读取,必须通过controller来承上启下,通信都是单向的
  • mvvm的view 和 viewModel可以互相通信,界面数据从viewmodel中获取

1、MVVM 设计模式,是由 MVC(最早来源于后端)、MVP 等设计模式进化而来。

  1. M - 数据模型(Model),简单的JS对象
  2. VM - 视图模型(ViewModel),连接Model与View
  3. V - 视图层(View),呈现给用户的DOM渲染界面
  4. 最核心的就是ViewModel :它主要的作用:对View中DOM元素的监听和对Model中的数据进行绑定,当View变化会引起Model中数据的改动,Model中数据的改动会触发View视图重新渲染,从而达到数据双向绑定的效果,该效果也是Vue最为核心的特性。
  5. 使用 MVVM 设计模式的前端框架很多,其中渐进式框架 Vue 是典型的代表,并在开发使用中深得广大前端开发者的青睐,我们这篇就根据 Vue 对于 MVVM 的实现方式来简单模拟一版 MVVM 库。

2、什么是mvc 软件可以分为三个部分

1、模型(model) :数据处理视图
2、(view):数据展示控制器
3、(controller)业务处理

在 MVC 模式中,除了 Model 和 View 层以外,其他所有的逻辑都在 Controller 中,Controller 负责显示页面、响应用户操作、网络请求及与 Model 的交互,随着业务的增加和产品的迭代,Controller 中的处理逻辑越来越多、越来越复杂,难以维护。为了更好的管理代码,为了更方便的扩展业务,必须要为 Controller “瘦身”,需要更清晰的将用户界面(UI)开发从应用程序的业务逻辑与行为中分离,MVVM 为此而生。

3、区别:

MVVM通过数据来显示视图,而不是通过节点操作

  1. MVVM主要解决了MVC中大量的DOM操作,使页面渲染性能降低,加载速度慢,影响用户体验的问题
  2. MVC中的Control在MVVM中演变成viewMode

16-1、vue的生命周期

vue细节讲解_第2张图片

​ 1、创建阶段 beforecreate(loading) created(结束loading) 经历了什么:组件通讯props中

​ 2、挂在阶段 beforMount(ajax请求) Mounted(节点操作) 经历了什么:把实例数据挂在到view中

​ 3、更新阶段 beforeUpdata Updtaed 经历了什么:虚拟diff和dom算法 updated:data和页面都已经更新完成
4、销毁阶段beforeDestrory(可以取消ajax请求) destroryed 经历了什么:清除事件监听,此时组件已经被销毁,data,methods等都不可用

16-2、created和mounted的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。

mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。在 mounted 中可以访问操作 DOM

调用异步请求在哪个阶段

可以在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data 已经创建,

但是本人推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:能更快获取到服务端数据,减少页面 loading 时间

16-3、 比如有时候我们修改了某个数据,如果直接渲染到真实dom上会引起整个dom树的重绘和重排,有没有可能我们只更新我们修改的那一小块dom而不要更新整个dom呢?
diff算法能够帮助我们。发现有不一样的地方就直接修改在真实的DOM上 ,diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

16-4、DOM diff原理

  • 如果元素类型发生变化,直接替换
  • 如果是文本,则比较文本里面的内容,是否有差异,如果是元素就需要比较当前元素的属性是否相等,会先比较key, 在比较类型 为什么 react中循环 建议不要使用索引 ,如果纯为了展示 那可以使用索引

为什么使用key?

当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容

**key的作用主要是为了高效的更新虚拟DOM。**需要为每一项 item 设置唯一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值对比,较快地定位到 diff

17、什么是VueX?

vueX是一个专门为vue.js应用程序开发的全局状态模式,它采用集中式管理所有组件是公共状态。并以响应的规则保证状态以一种可预测的方式发生变化

为什么使用vuex ?

vuex的出现就是解决多个组件数据通讯

Vuex的几中属性:

有五种分别是store、state、 getter、 mutation

使用步骤是什么

1、创建一个store (可以理解为数组之间的data)

Store就是vuex的公共状态,用于保存公共数据 组件通过this.$store.stare.xxx来或获取

Getter (类似computed) {computed 是属性调用有缓存的功能:而methods是函数调用}

Mutations:修改state的唯一方式

2、创建state数据交给store来保管

3、将创建好的 store注入到vue实例当中

4、组件中使用state中的数据

场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车

二十九、vuex是什么?怎么使用?哪种功能场景使用它?

  • state 用来数据共享数据存储
  • mutation 用来注册改变数据状态
  • getters 用来对共享数据进行过滤操作
  • action 解决异步改变共享数据

场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车

vuex是vue生态系统中的状态管理,用来管理vue中的所有组件状态。

1、state状态,还有mapState映射状态每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

2、getter相当于store的计算属性,主要用来过滤一些数据

3、Mutation 改变vuex中store状态唯一方法就是提交mutation,可传入额外参数,是一个同步函数。

4、Action 类似mutation,但是是异步的,view层通过store.dispath分发action

5、module 当应用比较复杂,可以将store分割成模块

或者:

1、Vuex就是一个仓库,仓库里面放了很多对象其中state就是数据源存放地

2、getters 可以对State进行计算操作

3、Action 类似于 mutation,不同在于:二、Action 提交的是 mutation

Vuex使用dispatch和commit来调用mutations的区别

dispatch:含有异步操作,例如向后台提交数据,写法:this.$store.dispatch(‘mutations方法名’,值)

commit:同步操作,写法this.$store.commit(‘mutations方法名’,值) 来进行修改数据

this.$store.dispatch("updateUserInfo", 'nick');

// this.$store.commit("increment", 'nick');

18、(1)keep-alive是什么

第一:应用场景

  1. 商品列表页点击商品跳转到商品详情,返回后仍显示原有信息
  2. 订单列表跳转到订单详情,返回,等等场景。

第二:keep-alive 的生命周期

  • 初次进入时
  1. created > mounted > activated
  2. 退出后触发 deactivated
  • 再次进入
  1. 只会触发 activated
  • 事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中

在项目中使用

一、更改App.vue

<div id="app" class='wrapper'>

   <keep-alive>
      <!-- 需要缓存的视图组件 -->
      <router-view v-if="$route.meta.keepAlive"> </router-view>
    </keep-alive>

    <!-- 不需要缓存的视图组件 --> 
    <router-view v-if="!$route.meta.keepAlive"> </router-view>

 </div>

二、在路由中设置keepAlive

 meta: {

    keepAlive: true,
    title: '商品管理'

  }

三、更改 beforeEach 钩子

这一步是为了清空无用的页面缓存。 假设现在A、B两个页面都开启的缓存:

  • 若第一次进入A页面后退出,再次进入页面时,页面不会刷新。这和目前的业务逻辑不符。我们想要的结果是A页面前进后返回,页面保持不变,而不是退出后重新进入保持不变。
  • 在进入过A页面后进入B页面,经过测试后发现,B页面竟然会显示A页面的缓存,尽管url已经改变~
  • 为了解决这个问题,需要判断页面是在前进还是后退。 在beforeEach钩子添加代码:
let toDepth = to.path.split('/').length 

let fromDepth = from.path.split('/').length 

if (toDepth < fromDepth)

 { // console.log('后退。。。')

 from.meta.keepAlive = false

 to.meta.keepAlive = true
}

https://juejin.im/post/5b4320f9f265da0f7f4488f6

2、keep-alive是Vue.js的一个内置组件。< keep-alive > 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。它自身不会渲染一个 DOM 元素,keep-alive用于保存组件的渲染状态。也不会出现在父组件链中。 当组件在 < keep-alive > 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

在vue页面当中created只执行一次在页面使用keep-alive

离开这个缓存的组件 执行 deactivated(){ 可在里面写逻辑 }

重新进入这个组件则 执行 activated (){可在里面写逻辑 }

keep-alive它提供了include(include定义缓存白名单,keep-alive会缓存命中的组件)与exclude(exclude定义缓存黑名单,被命中的组件将不会被缓存)两个属性,max定义缓存组件上限允许组件有条件地进行缓存。

记住:包含了keep-alive的组件,created()、mounted()都只会触发一次。但是activated每一次进入组件,都会触发一次哦~

​ keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中; 使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

3、一个场景

用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。 总的来说,keep-alive用于保存组件的渲染状态。

18、(2)缓存路由

​ keep-alive是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。我们可以0使用以下方式设置某些页面是否被缓存:

xport default [

  {

​    path: '/A',

​    name: 'A',

​    component: A,

​    meta: {

​      keepAlive: true // 需要被缓存}

  }

19、虚拟 DOM

  • key的作用主要是为了高效的更新虚拟DOM?

我的理解:v-for更新dom节点时如果不加key则就会数据将会改变顺序而vue也会复用当前的数据

  • 虚拟 dom 为什么效率比较高?

1、是一个结构类似与真节点对象 ,在内存中运行在内存中运行

2、对节点操作优化

3、对事件优化

20、封装过什么组件

Vue组件封装过程

1、首先,使用Vue.extend()创建一个组件

2、然后,使用Vue.component()方法注册组件

3、接着如果子组件需要数据,可以在props中接受定义

4、子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

子组件怎么使用父组件的方法

对于一个带有v-model的组件原理大概有以下几点:

1、首先带有v-model的父组件通过绑定的value值(即v-model的绑定值)传给子组件

2、然后子组件通过 prop接收一个 value;

3、最后子组件利用 $emit 触发 input 事件,并传入新值value给父组件;

4、vue会自动实现数据更新。

21-1、双向数据绑定原理,具体怎么做的?

原理:

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

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

在Vue中获得真实的节点

1、给元素添加ref属性

2、通过vm.$ref 获取这格属性

Mvvm view 视图ui组件 viewmodel 是一个同步的view和model的对象

Model代表数据模型

具体实施方法:

双向数据绑定原理:双向数据绑定 = 单项数据绑定(v-bind) + 事件(v-on)

NPM是随同NodeJS一起安装的包管理工具

怎么做:

1、实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者

2.、实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

3、实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

vue细节讲解_第3张图片

21-2、响应式数据/双向绑定原理

Vue 数据双向绑定主要是指:数据变化更新视图,视图变化时更新数据

其中,View(视图层)变化更新Data,可以通过事件监听的方式来实现,所以 Vue数据双向绑定的工作主要是如何根据Data变化更新View(视图层)。

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)

obj要定义属性的对象。prop要定义或修改的属性的名称或 Symbol

descriptor 要定义或修改的属性描述符。

简述:

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项Vue 将遍历此对象所有的 property(property属性意思)并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。(getter :是一种获得属性值的方法setter:是一种设置属性值的方法。)

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。

它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖之后当依赖项的 setter 触发时,会通知 watcher而使它关联的组件重新渲染。

这句话我的理解就是组件数据属性记录为依赖项 通知订阅者Watcher而使它关联的组件重新渲染

vue是一个经典的观察者模式

vue细节讲解_第4张图片

深入理解:

  • 监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。

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

  • 订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新——这是一个典型的观察者模式

  • 订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。

22-1、编程式导航

query和parms:

parmas: 那如果直接把id值写进发送的url里面呢

< router-link :to="{ name: 'W', params: { id:'1234',age:'12' }}"/>

这里只能用name不能用path,不然会直接无视掉params中的内容

query:< router-link :to="{ path: '/W', query: { id:'1234',age:'12' }}"/>

http://localhost:8080/#/hhhhhhh?id=1234&age=12

path是目标页面地址

parmas:且可以通过 this.$route.parmas.id 获取到传过来的 id 值,但如果 刷新页面,传过来的 id 值和 age 值就会丢失

query:但这两种我们都要用req.query.id来获取里面的id值

query 发送的就用 this.$route.query 接收

params 发送的就用this.$route.params 接收

axios

axios({ method: 'post',

 url: 'https://upload.qiniup.com/putb64/-1',

 headers: { 'Content-Type': 'application/octet-stream', Authorization: `UpToken ${token}` },

 data: imgSrc.split('base64,')[1] // 直接传递内容 })

22-2、声明式导航

声明式导航是写在组件的template中,通过router-link来触发。

<router-link :to='{path:"/detail",query:{obj:value}}'></router-link>

都是 this.$route.params

23、参数传输的方式

父子之间的传值

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

子传给父是:$emit方法传递参数.

​ 兄弟之间的传值:使用eventBus有个中间站 使用它接受数据和传递数据

插槽的用法

定义:插槽就是将定义在父组件内的内容分配到子组件上。

  1. 父组件把数据给子组件,父=>子
  2. 子组件把数据给插槽,并暴露给父组件接口
  3. 父组件调用子组件的插槽slot接口和数据

24、说说你对vue的理解

使用vue不必担心布局更改和类名重复导致的js重写,因为它是靠数据驱动双向绑定,底层是通过Object.defineProperty() 定义的数据 set、get 函数原理实现。2、组件化开发,让项目的可拓展性、移植性更好,代码重用性更高,就好像农民工建房子,拿起自己的工具包就可以开工。项目经理坐等收楼就好。3、单页应用的体验零距离接触安卓原生应用,局部组件更新界面,让用户体验更快速省时。4、js的代码无形的规范,团队合作开发代码可阅读性更高

或者:

一个用于创建 web 交互界面的库,是一个精简的 MVVM。它通过双向数据绑定把 View 层和 Model 层连接了起来。实际的 DOM 封装和输出格式都被抽象为了Directives (指令)和 Filters(过滤)

组件化:把一个单页应用中的各个模块拆分到一个个组件当中,或者把一些公共的部分抽离出来做成一个可复用的组件。所以组件化带来的好处就是,提高了开发效率,方便重复使用,使项目的可维护性更强。

虚拟DOM,当然,这个不是vue中独有的。

缺点:基于对象配置文件的写法,也就是options写法,开发时不利于对一个属性的查找

25、说说你遇到的难题(项目难点必问)

以前遇到的问题基本都解决了,解决后就感觉没那么难了说下;

那我最近遇到的问题吧

路由变化页面数据不刷新问题

出现这种情况是因为依赖路由的params参数获取写在created生命周期里面,因为相同路由二次甚至多次加载的关系 没有达到监听,退出页面再进入另一个文章页面并不会运行created组件生命周期,导致文章数据还是第一次进入的数据。

这种情况一般出现在vue-router的history模式下,初次进入会执行钩子函数,再次进入时则不会。

解决方案: 监听路由变化

watch : {//方法1       
     "$route" (to, from) { //监听路由是否变化             
     if(to.path.indexOf('/home') > -1) { // 判断条件1  判断传递值的变化               
         //获取数据                
        this.initData()            
     }        
   }     

  或者

​    //方法2  
   '$route'(to, from) {    
    if (to.path == "/page") {  /// 判断条件2  监听路由名 监听你从什么路由跳转过来的       
      this.message = this.$route.query.msg        
     }  
   }  
 }

26、vue router的搭建方式

1、引入 路由插件的js文件

2、 创建几个组件

3 、通过 VueRouter 来创建一个路由的实例,并且在参数中配置好路由规则

4 、将 路由实例 与 Vue实例关联起来,通过 router 属性

5、 在页面中使用 router-link 来定义导航(a标签) 路由路口

6 、在页面中使用 router-view 来定义路由出口(路由内容展示在页面中的位置)

27、vuex的搭建方式

1、首先在vue.js开发环境中 vuex npm install vuex --save;

2、然后在main.js中创建store对象

3、在然后在vue实例化的时候加入store对象:

4、在src下新建一个store文件夹,创建一个index.js:

5、import vuex from 'vuex'

28、vue常用修饰符

.prevent:提交时间不再重载页面 阻止事件的默认行为,

< a href=“http://www.baidu.com” @click.prevent=“test4”>百度一下< /a >

//阻止a标签跳转,仅执行函数test4

.stop:阻止单击事件冒泡

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

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

29、Vue中this.$router.push(参数) 实现页面跳转

很多情况下,我们在执行点击按钮跳转页面之前还会执行一系列方法,这时可以使用 this.$router.push(location) 来修改 url,完成跳转。

push 后面可以是对象,也可以是字符串

vue基础篇

1、css只在当前组件起作用 答:在style标签中写入scoped即可 例如:

2、v-if 和 v-show 区别 答:v-if按照条件是否渲染,v-show是display的block或none;

v-if 和 v-show 区分使用场景

v-if真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

v-show 就简单得多, 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 display 属性进行切换。

所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。

3、说到了v-if和v-show顺便谈一下 v-for 和 v-if 不建议用在一起

当 v-for 和 v-if 处于同一个节点时,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大,而真正要展示的数据很少时,这将造成很大的性能浪费

这种场景建议使用 computed,先对数据进行过滤

4、vue.js的两个核心是什么? 答:数据驱动、组件系统

5、vue几种常用的指令 答:v-for 、 v-if 、v-bind、v-on、v-show、v-else

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

7、v-on 可以绑定多个方法吗? 答:可以

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

9、什么是vue的计算属性? 答:在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。

10、vue等单页面应用及其优缺点 答:优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。 缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。

组件:组件是可复用的 Vue 实例,定义组件就是自定义一个标签。

* 全局组件

* 定义:Vue.component(name,options)

* name:组件名称

* options:组件配置参数

* 局部组件

* 定义:components配置参数

* 组件通讯

* 父->子: props

* 1. 在组件标签上定义一个属性

* 2. 在子组件中接收这个属性

vue细节讲解_第5张图片

11、vue中如何去掉 #

我们在vue项目中使用vue-router时,路径中会有 # 号,这样看着也不舒服。其实是因为路由有两种模式 hash 和 history,我们平时直接使用的是默认的hash,所以路径会有 # 号,因此我们只需要修改成 history 就可以了,如下图:
vue细节讲解_第6张图片

使用vue-router时候路径会有#号改为 mode:“history”

12、filter过滤器

16、Vue 的全家桶

Vue +cueClI(webpack +bable)+vueRouter +Vuex+axios

路由独享守卫 router 路由实例方法 router.afterEach()

17、$this.route当前路由信息

$this.router路由对象c

18、 vue实现按需加载组件

​ 组件的按需加载是项目性能优化的一个环节,也可以降低首屏渲染时间

1、 使用() => import(), 具体代码如下:

<template> 

<div>

 <ComponentA /> 

 <ComponentB />

 </div> 

 </template>

 <script> 

const ComponentA = () => import('./ComponentA') 

const ComponentB = () => import('./ComponentB') 

export default {

 // ... components: { ComponentA, ComponentB }, // 

... } 
</script>

​ 2、使用 resolve => require(['./ComponentA'], resolve),使用方法如下

<template>

 <div> 

 <ComponentA /> 

 </div> 

 </template> 

 <script> 

 const ComponentA = resolve => require(['./ComponentA'], resolve)

  export default { 

  // ... components: { ComponentA }, // ... } 

  </script>

也是组件通讯方式

19、provide和inject常用于局部刷新

​ provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中; 并且这对选项需要一起使用; 以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

使用场景:

​ vue中局部组件刷新,可以使用 provide / inject方法,在App.vue中添加刷新方法,路由初始状态是显示的

1、首先需要修改App.vue

<template>
  <div id="app">
    <div>
      <router-view v-if="alive" />
    </div>
  </div>
</template> 
  
<script>
export default { 
  name: 'App', 
  provide() { 
    return { 
    reload: this.reload 
    } 
  },

  data() { 
   return { 
    alive: true 
    } 
  }, 
  methods: {reload() {this.alive= false 
    this.$nextTick(() => { this.alive = true })}
   }
  }
</script>

2、其次到需要刷新的页面进行引用

inject: ['reload'],

 this.reload()

Vue2.x组件通信有哪些方式?

19-1、parent和children获取父子组件实例

parent: children:子实例

父组件 mounted(){ console.log(this.$children) //可以拿到 一级子组件的属性和方法 //所以就可以直接改变 data,或者调用 methods 方法 }

子组件 mounted(){ console.log(this.$parent) //可以拿到 parent 的属性和方法 }

19-2、$refs 获取实例的方式调用组件的属性或者方法

父组件页面 子组件 mounted(){ console.log(this.$refs.home) //即可拿到子组件的实例,就可以直接操作 data 和 methods }

19-3、$root

mounted(){ console.log(this.$root) //获取根实例,最后所有组件都是挂载到根实例上 
console.log(this.$root.$children[0]) //获取根实例的一级子组件 
console.log(this.$root.$children[0].$children[0]) //获取根实例的二级子组件 }

19-4、v-slot

作用就是将父组件的 template 传入子组件

19-5、EventBus兄弟组件通信

1.就是声明一个全局Vue实例变量 EventBus ,

把所有的通信数据,事件监听都存储到这个变量上;

2.类似于 Vuex。但这种方式只适用于极小的项目

3.原理就是利用emit 并实例化一个全局 vue 实现数据共享

在 main.js

Vue.prototype.$eventBus=new Vue() // 传值组件  // 接收组件 
 this.$ eventBus.$on("eventTarget",v=>{ 
   console.log('eventTarget',v); //这是eventTarget传过来的值
  })

4.可以实现平级,嵌套组件传值,但是对应的事件名eventTarget必须是全局唯一的

19-6、路由传参

1.方案一                     2.方案二

// 路由定义

{                             {

  path: '/describe/:id',        path: '/describe/:id',

  name: 'Describe',             name: 'Describe',

  component: Describe           component: Describe

}

// 页面传参

this.$router.push({            this.$router.push({

  path: `/describe/${id}`,     name: 'Describe'

                                params: {

                                     id: id

                             }

})

// 页面获取

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

19-7、Vue.directive

场景:官方给我们提供了很多指令,但是我们如果想将文字变成指定的颜色定义成指令使用,这个时候就需要用到Vue.directive

全局定义

Vue.directive("change-color",**function**(el,binding,vnode){  
  el.style["color"]= binding.value;
 })

19-8、Vue.filter

场景:时间戳转化成年月日这是一个公共方法,所以可以抽离成过滤器使用

使用 在双花括号中 {{ message | capitalize }}
v-bind 中 < div v-bind:id=“rawId | formatId”>
全局注册 Vue.filter(‘stampToYYMMDD’, (value) =>{ // 处理逻辑 })
局部注册 filters: { stampToYYMMDD: (value)=> { // 处理逻辑 } }

20、Vue.set()

场景:当你利用索引直接设置一个数组项时或你修改数组的长度时,由于 Object.defineprototype()方法限制,数据不响应式更新 不过vue.3.x 将利用 proxy 这个问题将得到解决 解决方案:

// 利用 set this.$set(arr,index,item)
// 利用数组 push(),splice()

区别在于Vue.set()是将set函数绑定在Vue构造函数上,this.$set()是将set函数绑定在Vue原型上。

this.$set为data中的某一个对象添加一个属性

在methods里面 点击事件这些 this.$set(this.student, 'age', 15)

对象添加属性之后,他的对象身上多了get和set方法,所以,此时我们再次操作该属性的时候,就会引起视图的更新啦

vm.$set 的实现原理是:

  • 如果目标是数组,直接使用数组的 splice 方法触发相应式;
  • 如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)

21、什么时候需要用到require.context
vue细节讲解_第7张图片

在Vue写的项目中,我把路由通过不同的功能划分成不同的模块在index.js中一个个导入(原谅ide的警告-.-),但是如果项目变大了之后,每次手动import会显得有些力不从心,这里可以使用require.context函数遍历modules文件夹的所有文件一次性导入到index.js中
vue细节讲解_第8张图片

这里我把require.context函数执行后的代码赋值给了files变量,files中保存了图一的以.js结尾的文件,files是个函数,我们分别调用者3个属性看看会返回什么

执行了keys方法返回了一个由匹配文件的文件名组成的数组id属性返回了匹配的文件夹的相对于工程的相对路径,是否遍历子目录,匹配正则组成的字符串

在使用require.context自动导入路由文件时发现一个问题,路由的顺序不是你期望的样子,因为webpack是根据你文件夹中文件的位置排序的,
这个 nginx.conf配置 server { listen 80; // 监听端口
server_name www.baidu.com; // 匹配来源
location / { //匹配路径
// 反向代理到http://127.0.0.1:3000 proxy_pass http://127.0.0.1:3000;
// 默认入口文件 index index.html index.htm index.jsp; }

  • nginx反向代理还能实现负载均衡

作者:*5102

链接:https://juejin.im/post/5e9f0bdce51d4546f5791989

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

vue时候需要定义一个标识符来给路由数组排序,这里我们给每个文件夹最上层的路由添加一个sort属性用于排序

22、vue 利用component组件和is属性实现动态组件

做一个 tab 切换时就会涉及到组件动态加载

 <!-- component标签创建动态组件,is属性指向谁,就显示哪个组件 -->

 <component :is="cmpName"></component> <br/>

      <button @click="changeCmp('cmpone')">第一个组件</button>

      <button @click="changeCmp('cmptwo')">第二个组件</button>

      <button @click="changeCmp('cmpthree')">第三个组件</button>

<component v-bind:is="currentTabComponent"></component>

但是这样每次组件都会重新加载,会消耗大量性能,所以 就起到了作用

<keep-alive>

  <component v-bind:is="currentTabComponent"></component>

</keep-alive>

这样切换效果没有动画效果,这个也不用着急,可以利用内置的

<transition>

<keep-alive>

  <component v-bind:is="currentTabComponent"></component>

</keep-alive>

</transition>

23、为什么vue中data是个函数

我们的data属性必须是一个函数,new Vue()中的data除外,因为new Vue中只有一个data属性。

原因:因为我们能抽离出来的组件,肯定是具有复用性的,它在项目中会存在多个实例。如果data属性值是一个对象时,那么它所有的实例都会共享这些数据,这是很麻烦的事情,你不能确保你的所有实例中的属性值都不会重复。

路由模块问题 — vue-router篇

24、前端实现登录拦截(路由拦截、http拦截)

大致流程: 在进行路由跳转时,利用vue-router提供的钩子函数 beforeEach() 对路由进行判断,符合条件next(),不符合便跳转到登录页面。在发送请求时,统一处理所有http请求和响应,用上 axios 的拦截器,通过配置http resquest interceptors为http头增加 Authorization字段,其内容为Token,通过配置http response interceptors对返回的数据处理。

24-1、路由跳转之前

router.beforeEach(async(to, from, next) => {

      NProgress.start() // 1、css进度条插件

      document.title = getPageTitle(to.meta.title) // 2、设置页面标题

      const hasToken = getToken() // 3

      或者  if (to.path !== '/login' && !localStorage.token) 

      // 确定用户是否已通过getInfo获得其权限角色4

     const hasRoles = store.getters.roles && store.getters.roles.length > 0

     // 基于角色生成可访问路由图5

     const accessRoutes=await store.dispatch('permission/generateRoutes', roles)

     // 动态添加可访问路由6

      router.addRoutes(accessRoutes)

     next({ ...to, replace: true }) // 设置replace:true,这样导航就不会留下历史记录

  }catch (error){

        await store.dispatch('user/resetToken')

        // 移除令牌并转到登录页以重新登录

    }
}

若当前token失效了,但是token依然保存在本地。这时候你去访问需要登录权限的路由时,实际上应该让用户重新登录。这时候就需要结合 http 拦截器 + 后端接口返回的http 状态码来判断。

新建一个http.js来配置axios拦截器,统一处理所有http请求和响应,就得用上 axios 的拦截器。通过配置http resquest interceptors为http头增加Authorization字段,其内容为Token,公司代码是有这个的。通过配置http response interceptors,当后端接口返回401 Unauthorized(未授权),让用户重新登录。

第一、请求拦截

http.interceptors.request.use((config)=>{

    config.headers.Authorization =Cookies.get('token');

    config.headers["Content-Type"]= 'application/json';

    return config;

},(err)=>{

    return Promise.reject(err);

})

第二、http response 响应拦截

//响应拦截

http.interceptors.response.use((res)=>{

        return res.data; 

},(err)=>{

    //提取状态值

    if(err.response.data.error.details){

        alert(err.response.data.error.details)

    }else{

        alert(err.response.data.error.message);

    }

    return err.response.data;
})

第三、 推荐使用Cookie来存储Token相比较而言,Web Storage(容易受到XSS攻击。)比Cookie更容易受到攻击。

24.1、全局导航钩子:

全局导航钩子主要有两种钩子:前置守卫、后置钩子

router.beforeEach((to, from, next) => { // do someting

  console.log('全局前置守卫:beforeEach -- next需要调用') //一般登录拦截用这个,也叫导航钩子守卫 
});

1. to: Route,代表要进入的目标,它是一个路由对象
2. from: Route,代表当前正要离开的路由,同样也是一个路由对象
3. next: Function,这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数

对于全局后置钩子

router.afterEach((to, from) => {  // do someting });

24.2、路由独享的钩子

即单个路由独享的导航钩子,它是在路由配置上直接进行定义的:

//路由独享守卫 router.js中进行设置 (beforeEnter对admin进行单独设置)

cont router = new VueRouter({

{ path: '/menus', component: Menus },

  {

    path: '/admin', component: Admin, beforeEnter: (to, from, next) => {

      alert("非登陆状态,请先登录")

      next("./login")

    }
}

置上直接定义 beforeEnter 守卫

meta字段(元数据)此外,vue-router中的meta,也就是类似于面包屑的功能

直接在路由配置的时候,给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,来进行一些操作。用它来做登录校验再合适不过了

24.3、组建内的导航钩子

组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的。

组建内守卫(进入beforeRouteEnter与离开beforeRouteLeave 再单独的组件中 例如Admin.vue中进行设置)

  beforeRouteEnter: (to, from, next) => {

    next(vm => {

      alert("hello" + vm.name);

    });

  }

  beforeRouteLeave(to, from, next) {
    if (confirm("确定离开吗?") == true) {

      next();

    } else {
      next(false);
    }
  }

我在实际的项目中只在组件内使用过beforeRouteLeave, 使用场景分别为一下三类情况:

(一) 、清除当前组件中的定时器

当一个组件中有一个定时器时, 在路由进行切换的时候, 可使用beforeRouteLeave将定时器进行清除, 以免占用内存:

beforeRouteLeave (to, from, next) { window.clearInterval(this.timer) //清楚定时器 next() }

(二) 、当页面中有未关闭的窗口, 或未保存的内容时, 阻止页面跳转

如果页面内有重要的信息需要用户保存后才能进行跳转, 或者有弹出框的情况. 应该阻止用户跳转

 beforeRouteLeave (to, from, next) {

 //判断是否弹出框的状态和保存信息与否

 if (this.dialogVisibility === true) {

  this.dialogVisibility = false //关闭弹出框

  next(false) //回到当前页面, 阻止页面跳转

 }else if(this.saveMessage === false) {

  alert('请保存信息后退出!') //弹出警告

  next(false) //回到当前页面, 阻止页面跳转

 }else {

  next() //否则允许跳转

 }

}

(三) 、保存相关内容到Vuex中或Session中

当用户需要关闭页面时, 可以将公用的信息保存到session或Vuex中

 beforeRouteLeave (to, from, next) {

  localStorage.setItem(name, content); //保存到localStorage中

  next()

}

路由元信息

在登录注册以后,谁需要登录才可以访问的合格设置

meta:{ requiresAuth:ture }

在路由下面(需要权限)如果用户未登录就next({ path:‘/login’ })

this.$router.push();跳转到不同的url,但这个方法回向history栈添加一个记录,点击后退会返回到上一个页面

this.$router.replace();不会有记录

this.$router.go(n);n可为正数可为负数。正数返回上一个页面,类似 window.history.go(n)

如何加载路由组件,动态加载路由组件,404页面路由配置,路由导航钩子使用)。如果在做后台系统,往往会涉及到权限系统,所以一般会采用动态配置路由,通过前后端约定的路由方式,路由配置文件更具不同用户的权限由后端处理后返。

25

25-1、active-class 是哪个组件的属性?

active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换;

25-2、vue-router 有哪几种导航钩子?

vue-router 的导航钩子,主要用来作用是拦截导航,让他完成跳转或取消。

25-3、$route 和 $router 的区别

$router.push({path:'home'});本质是向history栈中添加一个路由,在我们看来是 切换路由

$route 是一个跳转的路由对象

25-4、vue-router 是什么?它有哪些组件

路由就是SPA(单页应用)的路径管理器。再通俗的说vue-router就是WebApp的链接路径管理系统

SPA(single page application):单一页面应用程序,只有一个完整的页面;它在加载页面时,不会加载整个页面,而是只更新某个指定的容器中内容。单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式

Vue-router允许我们通过不同的url来访问不同的内容、实现多视图单页面的web应用

我的理解:路由允许我通过不同的的url来访问不同的内容,实现单页面多视图应用

优点:

  • 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
  • 基于上面一点,SPA 相对对服务器压力小
  • 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

缺点:

  • 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
  • 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
  • SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

25-5、vue路由hash模式和history模式实现原理分别是什么,他们的区别是什么?

  • hash 模式:

    • / #后面 hash 值的变化,不会导致浏览器向服务器发出请求,浏览器不发出请求,就不会刷新页面
    • 通过监听 hashchange 事件可以知道 hash 发生了哪些变化,然后根据 hash 变化来实现更新页面部分内容的操作。
  • history 模式:

    • history 模式的实现,主要是 HTML5 标准发布的两个 API,pushStatereplaceState,这两个 API 可以在改变 url,但是不会发送请求。这样就可以监听 url 变化来实现更新页面部分内容的操作

hash模式和history模式区别:

  • url 展示上,hash 模式有“#”,history 模式没有

  • 刷新页面时,hash 模式可以正常加载到 hash 值对应的页面,而 history 没有处理的话,会返回 404,一般需要后端将所有页面都配置重定向到首页路由

  • 兼容性,hash 可以支持低版本浏览器和 IE。

补充

虚拟DOM的原理

虚拟 DOM 的实现原理主要包括以下 3 部分:

1、用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
2、diff 算法 — 比较两棵虚拟 DOM 树的差异;
3、pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

优点:

1、保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;

2、无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;

3、跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
为什么虚拟DOM能5
减少DOM节点操作
对虚拟DOM的前后状态进行对比

缺点:

无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

MVVM的原理

1、MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;

2、Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。

3、这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。

在父子组件通讯过程中,子组件的哪个生命周期函数最先获取到props数据?

created 生命周期函数

vue单文件

组件的html,js,css组合到一个文件中,方便管理与维护,后缀为.vue文件。

结果如下:

    <template>
        // 组件的结构:html
    </template>
    <script>
        // 组件的js代码:配置、生命周期函数等
    </script>
    <style>
        // 组件的样式:css
    </style>

什么是模块化:

是从代码的角度来进行分析的,把一些可复用的代码,抽离为单个模块,便于项目的维护和开发;

什么是组件化:

是从UI界面来进行的分析,把一些可复用的UI元素,抽离为单独的组件;

vue是如何实现组件化的:

通过.vue文件来创建对应的组件;

vue文件里面包括三部分:

1、template 模板
2、script 行为
3、style 样式

Vue的父组件和子组件生命周期钩子函数执行顺序?

加载渲染过程:
父beforeCreate ->父 created ->父 beforeMount ->子 beforeCreate -> 子 created ->子 beforeMount -> 子 mounted -> 父 mounted

子组件更新过程:
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

父组件更新过程:
父 beforeUpdate -> 父 updated

销毁过程:
父beforeDestroy -> 子beforeDestroy -> 子 destroyed -> 父 destroyed

mvvm图示

vue细节讲解_第9张图片

你可能感兴趣的:(Vue,vue)