2022 VUE面试题

578 阅读41分钟

什么是 MVVM ?

MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。

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

ViewModel 通过双向数据绑定把 View 层和 Model 层连接起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

MVVM是把MVC的Controller和MVP的Presenter改成了ViewModel。

View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示。这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。

image.png

image.png 原文链接:blog.csdn.net/hrj970808/a…

MVVM模式的优点:

1、低耦合:视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

2、可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多 view 重用这段视图逻辑。

3、独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。

4、可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

原文链接:blog.csdn.net/hrj970808/a…

MVC

MVC是应用最广泛的软件架构之一,一般MVC分为:

Model( 模型 )、Controller( 控制器 )、View( 视图 )。

这主要是基于分层的目的,让彼此的职责分开。View一般通过Controller来和Model进行联系。Controller是Model和View的协调者,View和Model不直接联系。基本联系都是单向的。

image.png 1、View 传送指令到 Controller
2、Controller 完成业务逻辑后,要求 Model 改变状态
3、Model 将新的数据发送到 View,用户得到反馈

原文链接:blog.csdn.net/hrj970808/a…

mvvm 与 mvc 区别?它和其它框架(jquery)的区别是什么?哪些场景适用?

mvc和mvvm其实区别并不大,都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm 通过数据来显示视图层而不是节点操作。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

场景:数据操作比较多、频繁的场景,更加便捷。

原文链接:blog.csdn.net/sunhuaqiang…

MVP

MVP 模式将 Controller 改名为Presenter,同时改变了通信方向。\

image.png 1、各部分之间的通信,都是双向的。
2、View 与 Model 不发生联系,都通过 Presenter 传递。
3、View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

MVP 模式将 Controller 改名为Presenter,同时改变了通信方向。

vue

Vue 是一套构建用户界面的渐进式自底向上增量开发的 MVVM 框架,

Vue的优点

轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;
简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;
组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;
视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
虚拟DOM:dom 操作是非常耗费性能的, 不再使用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种方式;
运行速度更快:相比较于 react 而言,同样是操作虚拟 dom ,就性能而言, vue 存在很大的优势。
便于测试:组件化利于开发者对于单一组件进行测试,很少发生在整个页面下找不到是哪个地方报错的情况。 原文链接

Vue 解决了什么问题

① 虚拟 dom:dom 操作时非常耗性能的,不再使用原生的 dom 操作节点,极大的解放 dom 操作,但具体操作的还是 dom,不过是换了一种方式。

② 视图、数据、结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作。

③ 组件化:把一个单页应用中的各种模块拆分到一个一个单独的组件中,便于开发,以及后期的维护

原文链接:blog.csdn.net/thewar196/a…

Vue 的核心

Vue核心思想:数据驱动、组件化

一,数据驱动Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它让开发者省去了操作DOM的过程,只需要改变数据。Vue会通过Dircetives指令,对DOM做一层封装,当数据发生改变会通知指令去修改对应的DOM,数据驱动DOM变化,DOM是数据的一种自然映射。

Vue还会对操作进行监听,当视图发生改变时,vue监听到这些变化,从而改变数据,这样就形成了数据的双向绑定。

组件化 扩展HTML元素,封装可重用的代码。每一个组件都对应一个ViewModel。页面上每个独立的可视/可交互区域都可以视为一个组件。每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就进维护。页面是组件的容器,组件可以嵌套自由组合形成完整的页面。 原文链接:blog.csdn.net/weixin_4512…

vue 的单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

原文链接:blog.csdn.net/m0_67619362…

Vue 常用的修饰符

image.png

v-text 与{{}}与 v-html

{{}} 将数据解析为纯文本,不能显示输出 html
v-html 可以渲染输出 html
v-text 将数据解析为纯文本,不能输出真正的 html,与花括号的区别是
在页面加载时不显示双花括号
v-text 指令:
作用:操作网页元素中的纯文本内容。{{}}是他的另外一种写法
v-text 与{{}}区别:
v-text 与{{}}等价,{{}}叫模板插值,v-text 叫指令。
有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出 来,俗称屏幕闪动:

解决屏幕闪动的方法:

1.使用v-text渲染数据

2.使用{{}}语法渲染数据,但是使用v-cloak的指令(用来保持在元素上直到关联实例结束时候进行编译),v-cloak并不需要添加到每个标签,只要在el挂载的标签上添加就可以,并且为[v-cloak]添加CSS样式 display:none;

原文链接:blog.csdn.net/YD_family/a…

virtual-dom 原理实现(虚拟 dom)

virtual-dom(简称 vdom)的概念大规模的推广还是得益于 react 的出现,virtual-dom 也是 react 这个框架的非常重要的特性之一。相比于频繁的手动去操作 dom 而带来性能问题,vdom 很好的将 dom 做了一层映射关系,进而将在我们本需要直接进行 dom 的一系列操作,映射到了操作 vdom,而 vdom 上定义了关于真实 dom 进行的创建节点,删除节点,添加节点等一系列复杂的 dom 操作,并将这些操作放到 vdom 中进行,这样就通过操作 vdom 来提高直接操作的 dom 的效率和性能。

在vue的整个应用生命周期当中,每次需要更新视图的时候便会使用vdom,vdom算法是基于snabbdom算法所做的修改。

实现:

①用js对象构造一个虚拟的dom树,插入到文档中;
②状态变更时,记录新树和旧树的差异;
③把上面的差异构建到真正的dom中。

原文链接:blog.csdn.net/thewar196/a…

key

1、虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新旧虚拟DOM】的差异比较,比较规则如下:

2、key的对比规则:

1、旧虚拟DOM中找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没变,直接使用之前的真实DOM 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM 2、旧虚拟DOM中未找到与新虚拟DOM相同的key

创建新的真实DOM,随后渲染到页面

3、用index作为key可能会引发的问题:

1、若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ===> 界面效果没问底,但效率低

2、如果结构中还包含输入类的DOM:会产生错误DOM更新 ===> 界面有问题

4、开发中如何选择key?

1、最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值

2、如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

原文链接:blog.csdn.net/m0_53206841…

SPA单页面的理解,它的优缺点分别是什么?

是什么

SPA( single page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。 一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转 而页面的变化是利用路由机制实现 HTML 内容的变换,避免页面的重新加载。

优点

用户体验好,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
减少了不必要的跳转和重复渲染,这样相对减轻了服务器的压力

前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理

缺点

初次加载耗时多
不能使用浏览器的前进后退功能,由于单页应用在一个页面中显示所有的内容,所以,无法前进后退
不利于搜索引擎检索:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

SPA首屏加载速度慢的怎么解决

首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容;

加载慢的原因

网络延时问题
资源文件体积是否过大
资源是否重复发送请求去加载了
加载脚本的时候,渲染内容堵塞了

常见的几种SPA首屏优化方式

减小入口文件积
静态资源本地缓存
UI框架按需加载
图片资源的压缩
组件重复打包
开启GZip压缩
使用SSR

原文链接:blog.csdn.net/qq_44182284…

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

答: 共同点:都能控制元素的显示和隐藏;

不同点:

实现本质方法不同,

v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;

v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。

总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。

原文链接:blog.csdn.net/weixin_5478…

为什么避免v-if和v-for一起使用

vue2.x版本中,当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级;

vue3.x版本中,当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。

官网明确指出:避免 v-if 和 v-for 一起使用,永远不要在一个元素上同时使用 v-if 和 v-for。

可以先对数据在计算数据中进行过滤,然后再进行遍历渲染; 操作和实现起来都没有什么问题,页面也会正常展示。但是会带来不必要的性能消耗;

原文链接:blog.csdn.net/qq_44182284…

让CSS只在当前组件中起作用?

答:在组件中的style前面加上scoped

Vue初始化过程中(new Vue(options))都做了什么?

处理组件配置项;初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上;初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率;

初始化组件实例的关系属性,比如 p a r e n t 、 parent、parent、children、r o o t 、 root、root、refs 等

处理自定义事件

调用 beforeCreate 钩子函数

初始化组件的 inject 配置项,得到 ret[key] = val 形式的配置对象,然后对该配置对象进行响应式处理,并代理每个 key 到 vm 实例上

数据响应式,处理 props、methods、data、computed、watch 等选项

解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上

调用 created 钩子函数

如果发现配置项上有 el 选项,则自动调用 mount方法,也就是说有了el选项,就不需要再手动调用mount 方法,也就是说有了 el 选项,就不需要再手动调用 mount 方法,反之,没提供 el 选项则必须调用 $mount

接下来则进入挂载阶段

原文链接:blog.csdn.net/qq_44182284…

Vue数据双向绑定原理

实现mvvm的数据双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加setter,getter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:

1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者

2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数

3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

原文链接:blog.csdn.net/qq_44182284…

组件传参

3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,

(1)props / $emit 适用 父子组件通信

(2)ref 与 parent/parent / children 适用 父子组件通信

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

parent/parent / children:访问父 / 子实例

(3)EventBus (emit/emit / on) 适用于 父子、隔代、兄弟组件通信

这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

(4)attrs/attrs/listeners 适用于 隔代组件通信

attrs:包含了父作用域中不被prop所识别(且获取)的特性绑定(classstyle除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(classstyle除外),并且可以通过vbind="attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。

listeners:包含了父作用域中的(不含.native修饰器的)von事件监听器。它可以通过von="listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="listeners" 传入内部组件

(5)provide / inject 适用于 隔代组件通信

祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

(6)Vuex 适用于 父子、隔代、兄弟组件通信

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

原文链接:blog.csdn.net/m0_67619362…

vue 路由 路由面试题

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

vue-router 是 vue 的路由插件,

组件:router-link router-view

vue-router 导航钩子(路由守卫)?

1.导航钩子(路由守卫)的作用
vue-router 的导航钩子,主要用来作用是拦截导航,让他完成跳转或取消。

2.路由守卫分为三种

全局路由守卫、组件路由守卫、独享路由守卫。

1.全局导航钩子

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

注册一个全局前置守卫:

即对 整个单页应用(SPA) 中的所有路由都生效,所以当定义了全局的前置守卫,在进入每一个路由之前都会调用这个回调,那么如果你在回调中对路由的跳转条件判断出错,简单点就是死循环…因为你遗漏了某种路由跳转的情况,守卫会一直执行。所以在使用全局前置守卫的时候一定要判断清楚可能会出现的路由跳转的情况。 blog.csdn.net/a895544608/…

const router = new VueRouter({ ... });
router.beforeEach((to, from, next) => {
    // do someting
});

这三个参数 to 、from 、next 分别的作用:

to: Route,代表要进入的目标,它是一个路由对象

from: Route,代表当前正要离开的路由,同样也是一个路由对象

next: Function,这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数

a. next():进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是 confirmed(确认的)
b. next(false):这代表中断掉当前的导航,即 to 代表的路由对象不会进入,被中断,此时该表 URL 地址会被重置到 from 路由对应的地址
c. next(‘/’) 和 next({path: ‘/’}):在中断掉当前导航的同时,跳转到一个不同的地址
d. next(error):如果传入参数是一个 Error 实例,那么导航被终止的同时会将错误传递给 router.onError() 注册过的回调

注意:next 方法必须要调用,否则钩子函数无法 resolved

对于全局后置钩子:

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

后置钩子并没有 next 函数,也不会改变导航本身,全局后置守卫是整个单页应用中每一次路由跳转后都会执行其中的回调。所以多用于路由跳转后的相应页面操作,并不像全局前置守卫那样会在回调中进行页面的重定向或跳转。

2.路由独享的钩子beforeEnter

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

cont router = new VueRouter({
    routes: [
        {
            path: '/file',
            component: File,
            beforeEnter: (to, from ,next) => {
                // do someting
            }
        }
    ]
});

至于他的参数的使用,和全局前置守卫是一样的

3.组件内的导航钩子

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

我们看一下他的具体用法:


const File = {
    template: `<div>This is file</div>`,
    beforeRouteEnter(to, from, next) {
        // do someting
        // 在渲染该组件的对应路由被 confirm 前调用
    },
    beforeRouteUpdate(to, from, next) {
        // do someting
        // 在当前路由改变,但是依然渲染该组件是调用
    },
    beforeRouteLeave(to, from ,next) {
        // do someting
        // 导航离开该组件的对应路由时被调用,点击其他组件时,
       // 判断是否确认离开。确认执行next();
        //**取消执行next**(false),留在当前页面。
    }
}

需要注意是:

beforeRouteEnter 不能获取组件实例 this,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例 this

但是并不意味着在 beforeRouteEnter 中无法访问组件实例,我们可以通过给 next 传入一个回调来访问组件实例。在导航被确认是,会执行这个回调,这时就可以访问组件实例了,如:

beforeRouteEnter(to, from, next) {
    next (vm => {
        // 这里通过 vm 来访问组件实例解决了没有 this 的问题
    })
}

注意,仅仅是 beforRouteEnter 支持给 next 传递回调,其他两个并不支持。因为归根结底,支持回调是为了解决 this 问题,而其他两个钩子的 this 可以正确访问到组件实例,所有没有必要使用回调

完整的导航解析流程
1.导航被触发
2.在失活的组件里调用离开守卫
3.调用全局的 beforeEach 守卫
4.在重用的组件里调用 beforeRouteUpdate 守卫
5.在路由配置里调用 beforEnter
6.解析异步路由组件
7.在被激活的组件里调用 beforeRouteEnter
8.调用全局的 beforeResolve 守卫
9.导航被确认
10.调用全局的 afterEach 钩子
11.触发 DOM 更新
12.在创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

routeroute 和 router 的区别

router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。。。

route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等。。

Vue 路由的实现

前端路由就是更新视图但不请求页面,

利用锚点完成切换,页面不会刷新

官网推荐用 vue-router.js 来引入路由模块

定义路由组件

定义路由,使用 component 进行路由映射组件,用 name 导航到对应 路由

创建 router 实例,传入 routes 配置

创建和挂载根实例

用 router-link 设置路由跳转

vue-router的两种模式(hash,history)

vue-router有两种模式,hash模式和histor1. hash模式(vue-router默认hash模式)

Hash 模式地址栏中有#,history 没有,history 模式下刷新,会 出现 404 情况,需要后台配置 使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值 可以使用 hashchange 事件来监听 hash 值的变化 HTML5 提供了 History API 来实现 URL 的变化。其中最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的 是,前者是新增一个历史记录,后者是直接替换当前的历史记录。

hash模式背后的原理是onhashchange事件

window.onhashchange=function(){
 let hash=location.hash.slice(1);
 document.body.style.color=hash;
}

(localtion是js里管理地址栏的内置对象,是window对象的一部分,可通过window.localtion访问,在w3cshool里的详细介绍) 由于hash发生变化的url都会被浏览器记录下来,使得浏览器的前进后退都可以使用了,尽管浏览器没有亲求服务器,但是页面状态和url关联起来。后来人们称其为前端路由,成为单页应用标配。 比如www.abc.com/#/index,has…

2.history模式

history模式利用了HTML5 History Interface中新增的pushState()和replaceState()方法。MDN相关介绍(需要特定浏览器支持)。这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。

当使用history模式时,url就像正常的url,例如abc.com/user/id相比ha… 通过history api,我们丢弃了丑陋的#,但是有一个缺点,当刷新时,如果服务器中没有相应的相应或者资源,会分分钟刷出一个404来(刷新需要请求服务器)。所以history模式不怕前进,不怕后退,就怕刷新。

3 hash模式和history模式相比较

pushState()设置新的url可以是和当前url同源的任意url;hash只可修改#后面的部分,只能设置当前url同文档的url。

pushState()设置的新url可与当前url一致,这样也会把记录添加到栈中;hash必须设置与当前url不同的url的,才会触发动作将记录添加到栈中。

pushState()通过stateObject参数可以添加任意类型的数据到记录中;hash只可添加短字符串。

pushState()可额外设置title属性供后续使用。

不过,hash模式也有比history模式优势的地方。

hash模式下,仅hash符号之前的url会被包含在请求中,后端如果没有做到对路由的全覆盖,也不会返回404错误。

history模式下,前端的url必须和实际向后端发起请求的url一致,如abc.com/user/id,后端如…

vue-router的实现原理(核心):

更新视图但不重新请求页面。

hash模式:通过#号后面的内容的更改,触发hashchange事件,实现路由切换
history模式:通过pushState和replaceState切换url,实现路由切换,需要后端配合

❄ vue-router 登陆权限的判断 vue-router的登陆权限判断主要是在全局钩子函数中进行的,我们在router.js文件中的定义路由里,将需要登陆权限的页面加上meta属性,值是对象的形式,然后在该对象中自定义一个属性,属性值就是一个Boolean值,这时候在main.js文件的全局钩子函数中进行判断,如果需要跳转的页面的自定义属性值为true,那么将进行判断其是否登录,如果没有登录,则告诉用户登录,如果有登录,那么进行页面跳转。

routes:[
	{
		path:"/home",
		name:"Home",
		components:Home
		meta:{requireAuth:true}
	}
]

vue-router怎么重定向页面?

路由中配置redirect属性

vue-router实现路由懒加载( 动态加载路由 )

使用原因:在单页应用中,如果没有应用懒加载,运用 webpack 打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时 原理:vue 异步组件技术:异步加载,vue-router 配置路由 , 使用 vue 的异步组件技术 , 实现按需加载。

原文链接:blog.csdn.net/thewar196/a…

Vue 中路由跳转方式(声明式/编程式)

1.使用vue-router

2、router-link 【实现跳转最简单的方法】

<router-link to='需要跳转到的页面的路径>

浏览器在解析时,将它解析成一个类似于`<a>` 的标签。

3.this.$router.push

vue-router怎么配置404页面?

1.为通配符,匹配所有路径,redirect:重定向到404页面

2.必须将此路由配置放到最后,否则则无法实现该功能

{
    name:'404',
    path:'/404.html',
    component: resolve => require(['../page/NotFound/view.vue'], resolve),
},
{
     path:'*',
     redirect:{
         name:"404"
     }
}

路由传参

vue 路由传参的使用场景一般都是应用在父路由跳转到子路由时,携带参数跳转。传参方式可划分为 params 传参和 query 传参,而 params 传参又可分为在 url 中显示参数和不显示参数两种方式,这就是vue路由传参的三种方式。

1.query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示;
2.如果用params又不想刷新后丢失参数,只能拼在路由path后面;

方式一:params 传参(显示参数)

params 传参(显示参数)又可分为 声明式 和 编程式 两种方式

1、声明式 router-link

该方式是通过 router-link 组件的 to 属性实现,该方法的参数可以是一个字符串路径,或者一个描述地址的对象。使用该方式传值的时候,需要子路由提前配置好参数,例如:

//子路由配置
{
  path: '/child/:id',
  component: Child
}
//父路由组件
<router-link :to="/child/123">进入Child路由</router-link>

2、编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好参数,例如:

//子路由配置
{
  path: '/child/:id',
  component: Child
}
//父路由编程式传参(一般通过事件触发)
this.$router.push({
    path:'/child/${id}',
})

在子路由中可以通过下面代码来获取传递的参数值

this.$route.params.id

方式二:params 传参(不显示参数) params 传参(不显示参数)也可分为 声明式 和 编程式 两种方式,与方式一不同的是,这里是通过路由的别名 name 进行传值的

1、声明式 router-link

该方式也是通过 router-link 组件的 to 属性实现,例如:

<router-link :to="{name:'Child',params:{id:123}}">进入Child路由</router-link>

2、编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好参数,不过不能再使用 :/id 来传递参数了,因为父路由中,已经使用 params 来携带参数了,例如:

//子路由配置
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由编程式传参(一般通过事件触发)
this.$router.push({
    name:'Child',
    params:{
    	id:123
    }
})

在子路由中可以通过下面代码来获取传递的参数值

this.$route.params.id 1 注意:上述这种利用 params 不显示 url 传参的方式会导致在刷新页面的时候,传递的值会丢失

方式三:query 传参(显示参数)

query 传参(显示参数)也可分为 声明式 和 编程式 两种方式

1、声明式 router-link

该方式也是通过 router-link 组件的 to 属性实现,不过使用该方式传值的时候,需要子路由提前配置好路由别名(name 属性),例如:

//子路由配置
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由组件
<router-link :to="{name:'Child',query:{id:123}}">进入Child路由</router-link>

2、编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好路由别名(name 属性),例如:

//子路由配置
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由编程式传参(一般通过事件触发)
this.$router.push({
    name:'Child',
    query:{
    	id:123
    }
})

在子路由中可以通过下面代码来获取传递的参数值

this.$route.query.id

原文链接:blog.csdn.net/liyunkun888…

vue组件中data为什么函数返回一个对象

组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data。如果单纯的写成对象形式,就使得所有组件实例共用了一份data,造成了数据污染。

new Vue 实例里,data 可以直接是一个对象

new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

vue中data的属性可以和methods中方法同名吗,为什么?

可以同名,methods的方法名会被data的属性覆盖;调试台也会出现报错信息,但是不影响执行;

原因:源码定义的initState函数内部执行的顺序:props>methods>data>computed>watch

原文链接:blog.csdn.net/qq_44182284…

VUE跨域、常用解决跨域的方法

一、VUE中常用proxy来解决跨域问题

1、在vue.config.js中设置如下代码片段

module.exports = {
  dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: { // 配置跨域
    '/api':{
        target:`http://www.baidu.com`, //请求后台接口
        changeOrigin:true, // 允许跨域
        pathRewrite:{
            '^/api' : '' // 重写请求
        }
    }
  },
}

2、创捷axioss实例时,将baseUrl设置为 ‘/api’

const http = axios.create({
  timeout: 1000 * 1000000,
  withCredentials: true,
  BASE_URL: '/api'
  headers: {
     'Content-Type': 'application/json; charset=utf-8'
   }
})

二、JSONP解决跨域

三、CORS是跨域资源共享

原文链接:blog.csdn.net/codingLeade…

请说出 vue.cli 项目中 src 目录每个文件夹和文件的用法

assets 文件夹是放静态资源;
components 是放组件;
router 是定义路由相关的配置;
view 视图;
app.vue 是一个应用主组件;
main.js 是入口文件

Vue 的生命周期

什么是vue生命周期?

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

v u e 生 命 周 期 的 作 用 是 什 么 ?

vue生命周期中有多个事件钩子,让我们在控制整个vue实例过程中更容易形成 好的逻辑。

v u e 生 命 周 期 总 共 有 几 个 阶 段 ?

总共分为8个阶段:创建前/创建后,载入前/后,更新前/后,销毁前/后。

1)创建前(beforeCreate)

对应的钩子函数为beforeCreate。此阶段为实例初始化之后,此时的数据观察和事件机制都未形成,不能获得DOM节点。

2)创建后(created)

对应的钩子函数为created。在这个阶段vue实例已经创建,仍然不能获取DOM元素。

3,载入前(beforeMount)

对应的钩子函数是beforeMount,在这一阶段,我们虽然依然得不到具体的DOM元素,但vue挂 载的根节点已经创建,下面vue对DOM的操作将围绕这个根元素继续进行;beforeMount这个阶段是过渡性的,一般一个项目只能用到一两次。

4,载入后(mounted)

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

5,更新前(beforeUpdate)

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

6,更新后(updated)

对应的钩子函数是updated。在这一阶段DOM会和更改过的内容同步。

7,销毁前(beforeDestroy)

对应的钩子函数是beforeDestroy。在上一阶段Vue已经成功的通过数据驱动DOM更新,当我们不再需要vue操纵DOM时,就要销毁Vue,也就是清除vue实例与DOM的关联,调用destroy方法可以销毁当前组件。在销毁前,会触发beforeDestroy钩子函数。

8,销毁后(destroyed)

对应的钩子函数是destroyed。 在销毁后,会触发destroyed钩子函数。 vue的生命周期的思想贯穿在组件开发的始终,通过熟悉其生命周期调用不同的钩子函数,我们可以准确的控制数据流和其对DOM的影响;vue生命周期的思想是Vnode和MVVM的生动体现和继 承。

image.png

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

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

D o m 渲 染 在 哪 个 周 期 就 已 经 完 成 ?

Dom渲染在mounted中就已经完成了。

vue中created与mounted区别

在created阶段,实例已经被初始化,但是还没有挂载至el上,所以我们无法获取到对应的节点,但是此时我们是可以获取到vue中data与methods中的数据的;

在mounted阶段,vue的template成功挂载在$el中,此时一个完整的页面已经能够显示在浏览器中,所以在这个阶段,可以调用节点了;

原文链接:blog.csdn.net/qq_44182284…

Vue中computed与method的区别

相同点: 如果作为模板的数据显示,二者能实现响应的功能,唯一不同的是methods定义的方法需要执行

不同点:

1.computed 会基于响应数据缓存,methods不会缓存;

2.diff之前先看data里的数据是否发生变化,如果没有变化computed的方法不会执行,但methods里的方法会执行

3.computed是属性调用,而methods是函数调用

原文链接:blog.csdn.net/qq_44182284…

computed与watch的区别

1、computed擅长处理的场景:一个数据受多个数据影响;watch擅长处理的场景:一个数据影响多个数据。
2、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
3、是否调用缓存:computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作。
4、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
5、computed不支持异步 ,当computed内有异步操作时无效,无法监听数据的变化;而watch支持异步。
6、computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)

原文链接:blog.csdn.net/m0_53206841…

父子组件生命周期图

挂载: parent beforeCreate => parent created => parent beforeMount => child beforeCreate => child created => child beforeMount => child mounted => parent mounted

更新: parent beforeUpdate => child beforeUpdate => child updated => parent updated

销毁: parent beforeDestroy => child beforeDestroy => child destroyed => parent destroyed

从以上能够看出:

挂载时,子组件是在父组件before mount后开始挂载,并且子组件先mounted,父组件随后

更新时,子组件是在父组件before update后开始更新,子组件先于父组件更新

销毁时,子组件是在父组件before destroy后开始销毁,并且是子组件先销毁,父组件随后。

父组件可以监听到子组件的生命周期吗?

通过 $emit 触发父组件的事件,

//父组件
<rl-child  :value="40"  @childMounted="childMountedHandle" />
method () {
  childMountedHandle() {
     // do something...
  }
},

// 子组件
mounted () {
  this.$emit('childMounted')
},

总结:其实就是父子组件通信,事件名和钩子函数相同

缺点:以上方法虽然可行,但每次都需要手动写一次 $emit 触发父组件的事件。

更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,

@hook 方法可以监听子组件的任何的生命周期。子组件不需要发布。直接在父组件中,插入子组件的地方,使用@hook.声明周期函数名="函数名"即可

//父组件
<rl-child  :value="40"  @hook:mounted="childMountedHandle"  />
method () {
  childMountedHandle() {
       // 子组件触发mounted,父组件就触发这个事件
  }
},

//子组件,什么也不需要操作


原文链接:blog.csdn.net/weixin_5951…

原文链接:blog.csdn.net/wzstd/artic…

原文链接:blog.csdn.net/wzstd/artic…

Vue绑定数据的几种方式

一、用双大括号 ‘{{}}’ 把数据给到页面

二、使用vue指令

v-model 将输入框的值与msg绑定 ,还可以是v-text v-html v-bind等

三、标签属性前加 ‘ :’ 绑定

四、数据前拼接字符串用${}

Vue-注册全局组件的两种方法

第一种:在main.js中直接注册

// 引入
import PageTools from '@/components/PageTools'
// 注册为全局组件
Vue.component('PageTools', PageTools)

缺点:如果我们需要注册的全局组件非常多,我们需要一个一个引入,然后分别调用Vue.component方法,main.js文件会变的很大,不好维护。

第二种:使用插件的形式注册 在统一注册的入口文件 中

// 引入
import PageTools from './PageTools'
export default {
  install(Vue) {
  // 注册全局组件
    Vue.component('PageTools', PageTools)
  }

入口文件注册插件(main.js)

import Components from './components'
Vue.use(Components)

原文链接:blog.csdn.net/crystal_iww…

Elementui 中的常用组件及其属性有哪些?

Container 布局容器
el-container外层容器
el-header顶栏容器
el-aside侧边栏容器
el-main主要内容容器
el-footer底栏容器

Dropdown 下拉菜单
el-container split-buton下拉按钮
el-container-menu下拉菜单
el-container-item下拉项\

Table 表格
Tabs 标签页
Form 表单
Pagination 分页
Message 消息提示

Vue 中指令有哪些

v-for:循环数组,对象,字符串,数字
v-on:绑定事件监听
v-bind:动态绑定一个或者多个属性
v-model:表单控件或者组件上创建双向绑定
v-if v-else v-else-if 条件渲染
v-show 根据表达式真假,切换元素的 display
v-html 更新元素的 innerhtml
v-text 更新元素的 textcontent
v-pre 跳过这个元素和子元素的编译过程
v-clock 这个指令保持在元素上知道关联实例结束编译
v-once 只渲染一次

Vue-Cli 自定义指令

使用Vue框架开发的同胞们在非常愉快的使用vue内置指令的同时,有时候因为业务的原因,难免想动一动DOM的底层,这时候,vue为我们提供了自定义指令的权利。那么自定义指令,当然得区分时局部定义还是全局定义(比如我们需要定义一个元素获取焦点时的指令):

局部定义指令:局部定义需要在单文件组件中的dirctives中进行

    directives: {
    focus: {
      /**在绑定元素插入DOM中定义 */
      inserted(e) {
        e.focus()
      }
    }
  }

全局定义指令:我们现在src目录下新建directive文件夹,在其中新建focus.js的文件

第一步: 编写focus.js的内容

    import Vue from 'vue'
 
/** 全局注册*/
Vue.directive('focus',{
  /**
   * 当被绑定元素插入到DOM时 */
  inserted(e) {
    e.focus()
  }
})

第二步:在main.js中注册

    import './directives/focus'

第三步: 在template中引用

    <h2>自定义指令</h2>
<input type="text" v-focus>

自定义指令中涉及到的钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置;
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用

自定义组件的案例:

  • 防抖
  • 图片懒加载
  • 一键 Copy的功能
  • 拖拽指令
  • 页面水印
  • 权限校验
    // 1.设置v-throttle自定义指令
Vue.directive('throttle', {
  bind: (el, binding) => {
    let throttleTime = binding.value; // 防抖时间
    if (!throttleTime) { // 用户若不设置防抖时间,则默认2s
      throttleTime = 2000;
    }
    let cbFun;
    el.addEventListener('click', event => {
      if (!cbFun) { // 第一次执行
        cbFun = setTimeout(() => {
          cbFun = null;
        }, throttleTime);
      } else {
        event && event.stopImmediatePropagation();
      }
    }, true);
  },
});
// 2.为button标签设置v-throttle自定义指令
<button @click="sayHello" v-throttle>提交</button>

原文链接:blog.csdn.net/qq_41802862…

vue自定义过滤器

过滤器是对即将显示的数据做进一步的筛选处理,然后显示,过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据
vue中的过滤器分为两种:全局过滤器局部过滤器

过滤器可以用在两个地方:双花括号插值和 v-bind 表达式

当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!

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

① 项目使用 keep-alive 时,可搭配组件的 name 进行缓存过滤。
②DOM 做递归组件时需要调用自身 name
③vue-devtools 调试工具里显示的组件名称是由 vue 中组件 name 决定的

keep-alive 的理解

概念:keep-alive 是 vue 的内置组件,当它动态包裹组件时,会缓存不 活动的组件实例,它自身不会渲染成一个 DOM 元素也不会出现在父组 件链中

提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;

作用: 在组件切换过程中将状态保留在内存中,防止重复渲染 DOM,减 少加载时间以及性能消耗,提高用户体验。

生命周期函数: Activated 在 keep-alive 组件激活时调用,deactivated在 keep-alive 组件停用时调用

v-modal的使用。

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

$ nextTick的使用

答:当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。

为什么vue采用异步渲染

vue是组件级更新,当前组件里的数据变了,它就会去更新这个组件。当数据更改一次组件就要重新渲染一次,性能不高,为了防止数据一更新就更新组件,所以做了个异步更新渲染。(核心的方法就是nextTick)

源码实现原理: 当数据变化后会调用notify方法,将watcher遍历,调用update方法通知watcher进行更新,这时候watcher并不会立即去执行,在update中会调用queueWatcher方法将watcher放到了一个队列里,在queueWatcher会根据watcher的进行去重,多个属性依赖一个watcher,如果队列中没有该watcher就会将该watcher添加到队列中,然后通过nextTick异步执行flushSchedulerQueue方法刷新watcher队列。flushSchedulerQueue中开始会触发一个before的方法,其实就是beforeUpdate,然后watcher.run() 才开始真正执行watcher,执行完页面就渲染完成啦,更新完成后会调用updated钩子。

image.png

原文链接:blog.csdn.net/qq_44182284…

BootStraps原理

响应式页面实现的四大核心要素(Bootstrap原理)

1、viewport计算当前设备的可视区域的大小

用法:<meta name="viewport" content="width=device-width">

width设置当前页面的宽度,device-width:当前设备的宽度

height设置当前页面的高度,用到的机会很少

user-scale设置是否允许用户缩放

initial-scale设置页面初始化的缩放比例

2、绝对单位改为相对单位

宽度由像素值(px)修改为百分值(%);

字体由像素值(px)修改为相对大小(em);

图片有像素值(px)修改为百分值(%);

3、网格布局

将HTML页面宽度等分为12列

修改盒子模型为IE的怪异盒子模型

* {
    box-sizing: border-box;
}

在标准下盒子模型中

* {
    box-sizing :content-box
}

一个块的总宽度 = width + padding + border + margin;

IE怪异盒子模型中

一个块的总宽度 = width + margin;(即width中已经包含paddingborder)

4、媒体查询

a、

媒体类型:当前是什么设备

    .screen屏幕(高度和宽度)

    .print:打印机
    
    .all:所有设备

操作符:

    and-逻辑与
    
    not-逻辑非
    
    only-逻辑唯一

媒体属性:

    width:宽度
    
    min-width:最小宽度
    
    max-width:最大宽度

b、在CSS中定义样式:

@media 媒体类型 操作符 (媒体属性) {CSS样式}

eg:

    PC:

        @media screen and (min-width: 992px) {
            footer>div {
                width: 24%;
            }
        }

    PAD:

        @media screen and (min-width: 768px) and (max-width: 991px) {
            footer>div {
                width: 48%;
            }
        }

    PHONE:

        @media screen and (max-width: 767px) {
            footer>div {
                width: 98%;
            }
        }

原文链接:blog.csdn.net/qq_39090575…

栅格系统的工作原理:

1.行(row)必须包含在.container(固定宽度)或.container-fluid(100%宽度)中,以便为其赋予合适的排列(aligment)和内补(padding)。
2.通过行(row)在水平方向创建一组列(column)。
3.自己内容应当放置于列(column)内,并且,只有列可以作为行(row)的直接子元素。
4.类似.row和.col-xs-4这种预定义的类,可以用来快速创建栅格布局。Bootstrap源码中定义的mixin也可以用来创建语义化布局。
5.通过为列设置padding属性,从而创建列与列之间的间隔(gutter)。通过为.row元素设置负值margin从而抵消为.container元素设置的padding,也就间接为行(row)所包含的列(column)抵消掉了padding。
6.栅格系统的列是通过指定1到12的值来表示其跨越范围。例如三个等宽的列可以使用三个.col-xs-4来创建。
7.如果一行(row)中包含了的列(column)大于12,多余的列所在的元素将作为一个整体另起一行排列。
8.栅格类适用于与屏幕宽度大于或等于分界点大小的设备,并且针对小屏幕覆盖栅格类。

原文链接:blog.csdn.net/qq_21794603…

如果一个组件在多个项目中使用怎么办?

** 方案一:npm 发布引用**

公共组件编写完成后,将其发布到 npm。发布流程如下:在www.npmjs.com 注册一个账号进入 common 的控制台,输入命令 npm login,按照提示输入刚注册的账号密码输入命令 npm publish 即可需要用该组件的项目通过 npm install 命令将公共组件以 node_module 的方式引入。另外,每次改动代码再次发布时,需要修改 package.json 文件中的版本号,不然发布不成功。

方案二:npm link

首先进入公共包,在控制台输入 npm link 这会创建一个软连接,并保存到目录 C:\Users\Administrator\AppData\Roaming\npm\node_modules 下面。然后进入 使用该公共组件的项目,在控制台输入 npm link common。

方案三:npm 本地 file 引用(推荐)

进入使用该公共项目的文件夹,在控制台输入命令:npm install ../common/ 其 中…/common/是 common 的相对路径,这里也可以输入绝对路径这样就将 common 这个工程以 node_module 的方式引入到需要使用的项目中了。可以 正常使用公共项目在 index.js 中导出的组件了。命令执行完后,package.json 里会多一条记录

原文链接:blog.csdn.net/yzkdcsdn/ar…

槽口请简述

插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制

大概分这几点,首先槽口(插槽)可以放什么内容?放在哪?什么作用?

可以放任意内容,在子组件中使用,是为了将父组件中的子组件模板数据正常显示。

具名插槽和匿名插槽,作用域插槽,说白了就是在组件上的属性,可以在组件元素内使用,

可以在父组件中使用 slot-scope 从子组件获取数据

Vue中watch用法

在vue中,使用watch来监听数据的变化;
1.监听的数据后面可以写成对象形式,包含handler方法,immediate和deep。
2.immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。
3.当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

    watch: {
    name: {
      handler(newName, oldName) {
      
      },
      deep: true,
      immediate: true
    }
  } 

原文链接:blog.csdn.net/qq_44182284…

Vuex是什么?怎么使用?

Vuex是实现组件全局状态(数据)管理的一种机制,可以方便实现组件数据之间的共享;

Vuex优点

Vuex集中管理共享的数据,易于开发和后期维护;能够高效的实现组件之间的数据共享,提高开发效率;存储在Vuex的数据是响应式的,能够实时保持页面和数据的同步;

Vuex重要核心属性包括:state,mutations,action,getters,modules.

state

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

mutations

mutations定义的方法动态修改Vuex 的 store 中的状态或数据。

action

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

getters

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

modules

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

什么情况下使用 Vuex?

如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可; 需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态;

Vuex和单纯的全局对象有什么区别?

Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

为什么 Vuex 的 mutation 中不能做异步操作?

每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

Vuex 流程

在 vue 组件里面,通过 dispatch 来触发 actions 提交修改数据的操作,

然后通过 actions 的 commit 触发 mutations 来修改数据,

mutations接收到 commit 的请求,就会自动通过 mutate 来修改 state,

最后由 store 触发每一个调用它的组件的更新

vuex 怎么请求异步数据

1.首先在 state 中创建变量

2.然后在 action 中调用封装好的 axios 请求,异步接收数据,commit 提交给 mutations Mutations 中改变 state 中的状态,将从 action 中获取到的值赋值给 state

vuex 中 action 如何提交给 mutation 的

Action 函数接收一个与 store 实例具有相同方法和属性的 context 对象,

可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 获取 state 和 getters

Vuex 页面刷新数据丢失怎么解决

需要做 vuex 数据持久化 一般使用本地存储的方案来保存数据 可以自己设计存储方案 也可以使用第三方插件

推荐使用 vuex-persist 插件,它就是为 Vuex 持久化存储而生的一个插件。不需要你手动存取 storage ,而是直接将状态保存至 cookie 或者 localStorage 中

(注实际开发中使用sessionStorage来保存,原因是localStorage在同一浏览器中多个账户登录保存到localStroage会出问题)

原文链接:blog.csdn.net/thewar196/a…

axios,其特点和常用语法

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。前端最流行的 ajax 请求库, react/vue 官方都推荐使用 axios 发 ajax 请求

特点:

基于 promise 的异步 ajax 请求库,支持promise所有的API
浏览器端/node 端都可以使用,浏览器中创建XMLHttpRequests
支持请求/响应拦截器
支持请求取消
可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
批量发送多个请求
安全性更高,客户端支持防御 XSRF,就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

常用语法

axios(config): 通用/最本质的发任意类型请求的方式
axios(url[, config]): 可以只指定 url 发 get 请求
axios.request(config): 等同于 axios(config)
axios.get(url[, config]): 发 get 请求
axios.delete(url[, config]): 发 delete 请求
axios.post(url[, data, config]): 发 post 请求
axios.put(url[, data, config]): 发 put 请求
axios.defaults.xxx: 请求的默认全局配置
axios.interceptors.request.use(): 添加请求拦截器
axios.interceptors.response.use(): 添加响应拦截器
axios.create([config]): 创建一个新的 axios(它没有下面的功能)
axios.Cancel(): 用于创建取消请求的错误对象
axios.CancelToken(): 用于创建取消请求的 token 对象
axios.isCancel(): 是否是一个取消请求的错误
axios.all(promises): 用于批量执行多个异步请求
axios.spread(): 用来指定接收所有成功数据的回调函数的方法\

原文链接:blog.csdn.net/qq_44182284…

什么是axios 拦截器

axios特性: 1、拦截请求和响应 2、取消请求 3、转换json 4、客户端防御XSRF等。

使用拦截器的原因:

若出现请求数多的情况下,我们将会用到 axios 的一个API:拦截器。 页面发送http请求,很多情况我们要对请求和其响应进行特定的处理, 如果每个请求都附带后端返回的token,我们需要在拿到response之前loading动画的展示等。

拦截器的分类:

拦截器分为 请求(request)拦截器和 响应(response)拦截器。

拦截器的使用: 在请求或响应被 then 或 catch 处理前拦截它们。

(1)、请求拦截器

原文链接:blog.csdn.net/YHLSunshine…

拦截器就是拦截每一次的请求和响应,然后进行相应的处理。请求拦截器,它可以统一在你发送请求前在请求体里加上token;响应拦截器,是在接受到响应之后进行的一些操作,比如,服务器返回登录状态失效,需要重新登录的时候,就给它跳到登录页面;

对SSR有了解吗,它主要解决什么问题?

Server-Side Rendering 我们称其为SSR,意为服务端渲染指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程;

解决了以下两个问题

seo:搜索引擎优先爬取页面HTML结构,使用ssr时,服务端已经生成了和业务想关联的HTML,有利于seo

首屏呈现渲染:用户无需等待页面所有js加载完成就可以看到页面视图(压力来到了服务器,所以需要权衡哪些用服务端渲染,哪些交给客户端)

缺点

复杂度:整个项目的复杂度
性能会受到影响
服务器负载变大,相于前后端分离务器只需要提供静态资源来说,服务器负载更大,所以要慎重使用

原文链接:blog.csdn.net/qq_44182284…

做过哪些Vue的性能优化?

编码阶段

  1. 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
  2. v-if和v-for不能连用
  3. 如果需要使用v-for给每项元素绑定事件时使用事件代理
  4. SPA 页面采用keep-alive缓存组件
  5. 在更多的情况下,使用v-if替代v-show
  6. key保证唯一
  7. 使用路由懒加载、异步组件
  8. 防抖、节流
  9. 第三方模块按需导入
  10. 长列表滚动到可视区域动态加载
  11. 图片懒加载

SEO优化

  1. 服务端渲染SSR
  2. 预渲染

打包优化

  1. 压缩代码
  2. Tree Shaking/Scope Hoisting
  3. 使用cdn加载第三方模块
  4. 多线程打包happypack
  5. splitChunks抽离公共文件
  6. sourceMap优化

原文链接:blog.csdn.net/qq_44182284…

Vue要做权限管理该怎么做?控制到按钮级别的权限怎么做?

具体详解查看Vue要做权限管理该怎么做?控制到按钮级别的权限怎么做 前端权限管理的意义

1、降低非法操作的可能性

2、尽可能排除不必要的请求,减轻服务器的压力

3、提高用户体验

前端权限控制的思路:

1、菜单控制:在登录请求当中,会得到权限数据,权限需要在多个组件之间共享,所以可以通过vuex保存数据并且展示相应的菜单,页面刷新的情况下会丢失数据,所以把权限数据存入sessionStorage中。

3、按钮控制:路由规则中可以添加元数据meta,通过路由对象可以得到当前的路由规则以及存储在路由规则中的元数据,自定义指令可以实现对按钮的控制

4、请求和响应控制:请求拦截和相应拦截的使用,请求方式约定restful

前端权限控制可以分为四个方面:

  • 接口权限
  • 按钮权限
  • 菜单权限
  • 路由权限

接口权限

接口权限目前一般采用jwt的形式来验证,没有通过的话一般返回401,跳转到登录页面重新进行登录

登录完拿到token,将token存起来,通过axios请求拦截器进行拦截,每次请求的时候头部携带token

路由权限控制

方案一

初始化即挂载全部路由,并且在路由上标记相应的权限信息,每次路由跳转前做校验

这种方式存在以下四种缺点:

  • 加载所有的路由,如果路由很多,而用户并不是所有的路由都有权限访问,对性能会有影响。
  • 全局路由守卫里,每次路由跳转都要做权限判断。
  • 菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译
  • 菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

方案二

初始化的时候先挂载不需要权限控制的路由,比如登录页,404等错误页。如果用户通过URL进行强制访问,则会直接进入404,相当于从源头上做了控制

登录后,获取用户的权限信息,然后筛选有权限访问的路由,在全局路由守卫里进行调用addRoutes添加路由

按需挂载,路由就需要知道用户的路由权限,也就是在用户登录进来的时候就要知道当前用户拥有哪些路由权限 原文链接:blog.csdn.net/ilovexiaomi…

Vue3有了解过吗?能说说跟Vue2的区别吗?

具体详解请点击Vue3有了解过吗?能说说跟Vue2的区别吗?

Vue3.0 的了解

大致有三个点,

第一个是关于提出的新 API setup()函数,

第二个说了对于 Typescript 的支持,最后说了关于替换 Object.defineProperty 为 Proxy 的支持。详细说了下关于 Proxy 代替带来的性能上的提升,因为传统的原型链拦截的方法,无法检测对象及数组的一些更新操作,但使用 Proxy 又带来了浏览器兼容问题。

原文链接:blog.csdn.net/thewar196/a…

Proxy 相比于 defineProperty 的优势

Vue3.0 摒弃了 Object.defineProperty,改为基于 Proxy 的观察者机制探索。

首先说一下 Object.defineProperty 的缺点:

①Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。 ②Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue2.X 里,是通过递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象才是更好的选择。

而要取代它的 Proxy 有以下两个优点

  1. 可以劫持整个对象,并返回一个新对象。
  2. 有多种劫持操作(13 种)

补充: Proxy 是 ES6 新增的一个属性,翻译过来的意思就是代理,用在这里表示由它来“代理”某些操作。Proxy 让我们能够以简洁易懂的方式控制外部对象的访问,其功能非常类似于设计模式中的代理模式。
Proxy 可以理解为,在目标对象之前设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。从而可以让对象只需要关注核心逻辑,达到关注点分离,降低对象复杂度等目的。

原文链接:blog.csdn.net/thewar196/a…

Vue3.0 是如何变得更快的?(底层,源码)

a. diff 方法优化 Vue2.x 中的虚拟 dom 是进行全量的对比。

b.Vue3.0 中新增了静态标记(PatchFlag):

在与上次虚拟结点进行对 比的时候,值对比带有 patch flag 的节点,并且可以通过 flag 的信息 得知当前节点要对比的具体内容化。hoistStatic 静态提升

Vue2.x : 无论元素是否参与更新,每次都会重新创建。

Vue3.0 : 对不参与更新的元素,只会被创建一次,之后会在每次渲染时 候被不停的复用。

c.cacheHandlers 事件侦听器缓存

默认情况下 onClick 会被视为动态绑定,所以每次都会去追踪它的 变化但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用 即可。

Vue与Angular以及React的区别?

基本概念

Angular 是一个应用设计框架与开发平台,用于创建高效、复杂、精致的单页面应用。

React 是一个用于构建用户界面的 JavaScript 库

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

三者比较

相同点

1.都是基于javascript/typescript的前端开发库,为前端开发提供高效、复用性高的开发方式
2.都有组件和模板的开发思想
3.各自的组件都有生命周期,不用的组件可以卸载,不占用资源
4.都支持指令,如样式、事件等的指令

不同点

1.创始和发行不同:Angular是由googl提供支持的,初始发行于 2016年9月;React由Facebook维护,初始发行于 2013年3月;Vue是由前google人员创建,初始发行于2014年2月
2.应用类型不同:Angular支持开发native应用程序、SPA单页应用程序、混合应用程序和web应用程序;React支持开发SPA和移动应用程序;Vue支持开发高级SPA,开始支持native应用程序
3.模型不同:angular基于MVC(模型-视图-控制器)架构;react和vue是基于Virtual DOM(虚拟的文档对象模型)
4、数据流流向不同:Angular使用的是双向数据绑定,React用的是单数据流的,而Vue则支持两者。
5. 对微应用和微服务的支持不同:Angular使用的是TypeScript,因此它更适合于单页Web应用(single page web application,SPA),而非微服务。相反,React和Vue的灵活性更适合微应用和微服务的开发。
6. 对原生应用的支持不同: React Native为iOS和Android开发原生应用;Angular的NativeScript已被原生应用所采用,特别是Ionic框架已经被广泛地运用在制作混合应用等方面;Vue的Weex平台正在开发之中,尚无下一步使之成为全面跨平台的计划。
7. 框架和库:Angular 是一个框架而不是一个库,因为它提供了关于如何构建应用程序的强有力的约束,并且还提供了更多开箱即用的功能。React 和 Vue 是是一种库,可以和各种包搭配。
8. 组件之间传值方式不同:Angular 中直接的父子组件,父组件可以直接访问子组件的 public 属性和方法,也可以借助于@Input 和 @Output 进行通讯。没有直接关系的,借助于 Service 单例进行通讯;React 组件之间通过通过prop或者state来通信,不同组件之间还有Rex状态管理功能;Vue组件之间通信通过props ,以及Vuex状态管理来传值

原文链接:blog.csdn.net/m0_53206841…

vue全家桶及项目架构

包含了vue-router(router.vuejs.org),

vuex(vuex.vuejs.org),

vue-resource(github.com/pagekit/vue…

再加上构建工具vue-cli,就是一个完整的vue项目的核心构成。

原文链接:blog.csdn.net/zhenghao357…

iframe的优缺点?

iframe也称作嵌⼊式框架,嵌⼊式框架和框架⽹页类似,它可以把⼀个⽹页的框架和内容嵌⼊在现有的⽹页中。

优点

  1. 解决加载缓慢的第三⽅内容如图标和⼴告等的加载问题

  2. Security sandbox

  3. 并⾏加载脚本

  4. ⽅便制作导航栏

    缺点

  5. iframe会阻塞主页⾯的Onload事件

  6. 即使内容为空,加载也需要时间

  7. 没有语意

原文链接:blog.csdn.net/m0_53206841…

diff 算法

diff算法.png

为什么只对对象劫持,而要对数组进行方法重写?

因为对象最多也就几十个属性,拦截起来数量不多,但是数组可能会有几百几千项,拦截起来非常耗性能,所以直接重写数组原型上的方法,是比较节省性能的方案