跳转到主要内容

面试题库

Vue 面试题 100 问

Vue 2/3 核心 100 问 + JS/跨域/CSS 预编译/SEO 等扩展,共 282 题。

  • 前端
  • Vue
  • 面试

Vue 面试题 100 问

来源:resource/面试题.zip → 01.Vue100问.pdf

::: danger 高频面试题 第11题,第13题,第18题,第20题,第21题,第31题,第33题,第35题, 第36题,第37题,第38题,第39题,第40题,第50题,第55题,第74题, 第83题,第94题 :::

1.简述一下你对 Vue 的理解

Vue 的作者是尤雨溪,一位华裔前 Google 工程师(Who) Vue 项目于 2014 年正式发布,至今已经有 6 年历史,而在 2020 年 9 月 18 日发布了 3.0.0 版本One Piece。(When) Vue 是一个渐进式 JavaScript 框架,它只负责视图层数据渲染功能,所以就需要很多第三方 库来完善更多的扩展功能,以便完成动态构建用户界面的目标。(What) Vue 技术体系应用的场景非常的多,包括 PC 端 SPA 网站项目、后台管理系统、移动端 Webapp 的 M 站开发、微信小程序的实现以及 App 应用程序的处理等,应该说包含了多端 多设备的不同应用面。(Where) 这是因为 Vue 有其编码简洁、体积小、运行效率高、遵循 MVVM 模式、轻松引入第三方插 件与类库使用,能够快速实现应用程序的开发。(Why) Vue 在国内不同类型公司都广受欢迎,包括大型厂家,美团、饿了吗、阿里等,而中小型企 业发展更追求速度与效率,所以对于 Vue 的需求也更为的明确。

2.声明式和命令式编程概念的理解

声明式编程 Declarative Programing,主要关注“我想要什么”,而不关注具体该怎么实现, 当你告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。声明式编程的计算在运 行时构建完成。 命令式编程 Imperative Programming,命令“机器”如何去做事情(how),这样不管你想要的 是什么(what),它都会按照你的命令实现,计算机会严格遵循你的指令,而不理会最后的结 果是不是你所想要的。命令式编程的计算在编译时构建完成。JavaScript 并非完全是命令式 编程,例如:数组的 map 方法,即为声明式编程。

3.Vue 有哪些基本特征

声明式编程(没有 DOM 操作) 响应式数据 双向数据绑定

4.vue 之防止页面加载时看到花括号解决方案有哪几种?

v-cloak 用于大段内容,这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v- cloak] { display: none } 一起用时,这个指令可以隐藏未编译的标签直到实例准备完毕

<style>
[v-cloak]{display:none}
</style>

利用 v-text、v-html 代替插值表达式,v-text 用于单个标签、v-html 用于带有标签的处理 {{}}插值表达式是 v-text 的缩写,最终还是会解析成 v-text 的模式

5.Vue 中 v-for 与 v-if 能否一起使用?

不能 这需要考虑到 v-for 与 v-if 的优先级顺序问题,当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中 如果对于整体循环内容的控制,建议将条件判断编写至 v-for 循环的外部 如果需要对每个循环内容进行条件判断的话,建议编写 computed 属性计算进行对应内容的 控制

6.vue 中 v-if 与 v-show 的区别以及使用场景

区别 手段:v-if 是通过控制 dom 节点的存在与否来控制元素的显隐;v-show 是通过设置 DOM 元素的 display 样式,block 为显示,none 为隐藏; 编译过程:v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件 监听和子组件;v-show 只是简单的基于 css 切换; 编译条件:v-if 也是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时 才开始局部编译; v-show 是惰性的,在任何条件下都被编译,然后被缓存,而且 DOM 元 素保留; 性能消耗:v-if 有更高的切换消耗;v-show 有更高的初始渲染消耗; 总结: v-if 判断是否加载,可以减轻服务器的压力,在需要时加载,但有更高的切换开销;v-show 调整 DOM 元素的 CSS 的 dispaly 属性,可以使客户端操作更加流畅,但有更高的初始渲染开销。如果 需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

7.v-on 可以监听多个方法吗

可以,利用对象设置的方式设置多个监听事件

8.v-on 绑定的修饰符有哪些?v-model 绑定的修饰符有哪

些?

v-on 绑定的修饰符主要包括:事件的修饰符:stop、prevent、capture、self、once 等,按 键修饰符:enter、tab、delete、esc、space 等,系统修饰键:ctrl、alt、shift 等。 v-model 绑定的修饰符主要包括:lazy、trim、number

9.Vue 中动态样式绑定的方式有哪些?

不管是 class 类样式还是 style 行内样式,要进行动态样式绑定都需要进行表达式的返回操 作,而 class 绑定时表达式返回的结果可以是:字符串、对象、数组,并且数组中可以包含 的内容包括字符串与对象类型。 而 style 绑定时表达式返回的结果是:对象、数组,数组中包含的是对象。

<inputtype="text"v-on="{ input:onInput, focus:onFocus,  blur:onBlur}">

10.Vue 能否通过下标的方式进行数组的响应式数据的修

改?Vue 能否通过路径的方式进行对象的响应式数据的修

改?为什么?

不能 响应式数据需要在 data 中进行设置,而 data 中设置的响应式数据内容都会被转绑给 vm 实 例对象,如果直接通过 this.xxx 设置的属性能够被挂载到 Vue 实例当中,但它们并不是响应 式数据。 对于数组 Vue 内部对数组提供了一系列变异的方法操作,是对原来的 Javascript 数组操作进 行了内部的重写,只不过 Vue 所提供的数组函数名称与 Javascript 所提供的名称保持一致而 已,而这些数组的方法主要包括:push、pop、shift、unshift、splice、sort、reverse 等 Vue 同样不能检测对象属性的添加或删除,但利用 Vue.set(object, key, value) / Vue.delete(Object,key) 方法可以向嵌套对象添加响应式属性,你还可以使用 vm.$set / vm.$delete 实例方法,它只是全局 Vue.set / Vue.delete 的别名 ::: danger 列表中的 key 设置 为什么 Key 一定需要使用唯一值,如果没有唯一值则需要生成,不建议使用 index 下标进行 key 的设 置?(详见:列表中的 key 设置.html 示例) :::

11.如果后台接口返回的循环数据没有唯一值,在 v-for 循

环中如何设置 key?

key 值在列表渲染的时候,能够提升列表渲染性能,为什么呢?首先得想想 Vue 的页面是如何渲 染的,主要分为以下几步: 将页面结构的文档构建成一个 vdom 虚拟数 页面有新的交互,产生新的 vdom 数,然后与旧数进行比较,看哪里有变化了,做对应的修 改(删除、移动、更新值)等操作(对比 react、小程序) 最后再将 vdom 渲染成真实的页面结构 key 值的作用就在第二步,当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架 会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的 效率。key 值如果不指明,默认会按数组的索引来处理,因而会导致一些类似 input 等输入框组件 的值出现混乱的问题。 不加 key,在数组末尾追加元素,之前已渲染的元素不会重新渲染。但如果是在头部或者中 间插入元素,整个 list 被删除重新渲染,且 input 组件的值还出现了混乱,值没有正常被更 新 添加 key,在数组末尾、中间、或者头部插入元素,其它已存在的元素都不会被重新渲染, 值也能正常被更新 因而,在做 list 渲染时,如果 list 的顺序发生变化时,最好增加 key,且不要简单的使用数组索引 当做 key,需要用唯一值当成 key。 如果后台接口返回的循环数据没有唯一值,那么可以在客户端利用 map 循环对原数组内容进行遍 历,然后返回经处理过带有唯一值的数组列表,那么在 v-for 循环的时候依旧设置的是唯一值数 据。

12.为什么在-HTML-中监听事件?

扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它 们。

13.vue 中 methods、watch、computed 之间的差别对

比以及适用场景

methods,watch 和 computed 都是以函数为基础的,但各自却都不同 computed:计算属性是基于其它的响应式依赖进行缓存的,只在相关响应式依赖发生改变 时它们才会重新求值。就算在 data 中没有直接声明出要计算的变量,也可以直接在 computed 中写入。计算属性默认只有 getter,可以在需要的时候自己设定 setter。数据量 大,并需要进行依赖计算的时候使用 computed,因为它会进行缓存处理,提升执行的性 能。computed 应用的场景:一个数据受多个数据的影响。 methods:首先 compunted 属性计算需要实现的目标利用 methods 方法都能够实现,但 是 compunted 基于缓存处理,而 methods 每当触发重新渲染时,调用方法将总会再次执行 函数,从目标性能上来看,如果两者都可以实现目标的话一般建议使用 compunted 而不是 methods。 watch:watch 和 computed 很相似,watch 用于观察和监听页面上的 vue 实例,大部分情 况下我们建议使用 computed,但如果要在数据变化的同时进行异步操作或者是比较大的开 销,那么 watch 为最佳选择。watch 为一个对象,键是需要观察的表达式,值是对应回调函 数。值也可以是方法名,或者包含选项的对象。如果在 data 中没有相应的属性的话,是不能 watch 的,这点和 computed 不一样。watch 应用的场景:一个数据影响多个数据。watch 监控除了编写 watch 对象,还可以利用 vm.$watch 进行 API 模式的监控操作。 immediate:组件加载立即触发回调函数执行 deep: 深度监听:为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象 内容的改变 总结:在 computed、methods、watch 方面,一个是计算,一个是调用、一个是观察,在语义 上是有区别的。计算是通过变量计算来得出数据,调用是方法的重复执行,而观察是观察一个特定 的值。

14.computed 属性计算函数能否传递参数?

可以 compunted 中定义属性计算函数,一般如果没有参数传递,可以直接 return 返回属性计算 的结果 但如果需要传递参数,则计算函数中需要进行 return fn(arg…),而这个返回的函数中可以设 置参数内容,最终属性计算的函数调用将会调用到 return 返回的这个函数内容。

15.Vue 实例中最为重要的三大部分是什么?

{{ compuntedFn(arg) }}
computed: {
compuntedFn: function () {
returnfunction (arg) {
return"compuntedResult"
};
},
},

不管是 Vue 也好或者其它的框架也罢,基本上面向对象以及组件化开发中实例对象都包含三个主 要部分内容: 属性:设置属性,给实例对象内容进行属性的设值操作。 事件:触发事件,由对象提供事件,触发事件以后进行对应功能的处理。 方法:调用方法,方法的调用一般由第三方触发并调用对应的方法内容。 属性、事件是对象本身的操作,而方法一般交由第三方去操作对象本身内容,比如点击按钮去修改 对象的属性操作。

16.组件在定义与使用的时候一般需要注意哪些细节?

组件中 data 的定义必须是一个函数:每个组件需要拥有自己的数据内容,并且不希望干扰到 其它的组件内容,如果定义成 Object 对象的话,那么将会作用于所有的组件内容,在一个组 件中进行 data 数据修改将会影响到其它组件。所以我们需要将它定义成函数的形式,函数返 回的对象才是真正意义上数据的存储仓库(data),这样设计的目的是为了让每个组件间的数据 都是独立的,互不影响。 当组件的嵌套与 Html5 的规范产生冲突时我们可以使用 is 属性来解决冲突,比如: 组件上的所有事件都是 vue 自定义事件 props 特性属性与 vue 指令在组件中都不会继承,而非 props 特性属性则会进行继承处理

17.Vue 中如何实现块状内容的输出?

块状内容在页面中将不会进行块状标签的输出 Vue:template React:fragment,<> 小程序:block

18.简述一下组件的生命周期

在进行组件化项目开发的时候都会存在一个组件的生命周期概念,像 Vue、React、小程序等等, 无一例外,而通常情况组件的生命周期主要分成三个阶段,包括:创建、更新以及销毁阶段。 Vue 的生命周期钩子函数主要包括:

  1. beforeCreate(): 在实例初始化之后调用, data 和 methods 都还没有初始化完成, 通过 this 不 能访问
  2. created(): 此时 data 和 methods 都已初始化完成, 可以通过 this 去操作, 可以在此发 ajax 请 求
  3. beforeMount(): 模板已经在内存中编译, 但还没有挂载到页面上, 不能通过 ref 找到对应的标 签对象
  4. mounted(): 页面已经初始显示, 可以通过 ref 找到对应的标签, 也可以选择此时发 ajax 请求
  5. beforeUpdate(): 在数据更新之后, 界面更新前调用, 只能访问到原有的界面
  6. updated(): 在界面更新之后调用, 此时可以访问最新的界面
  7. beforeDestroy(): 实例销毁之前调用, 此时实例仍然可以正常工作
  8. destroyed(): Vue 实例销毁后调用, 实例已经无法正常工作了
  9. deactivated():组件失活, 但没有死亡
  10. activated(): 组件激活, 被复用
  11. errorCaptured(): 用于捕获子组件的错误,return false 可以阻止错误向上冒泡(传递)

我们通常在 created()/mounted()进行发送 ajax 请求,启动定时器等异步任务,而在

beforeDestory()做收尾工作,如: 清除定时器操作。

不过需要注意的是 mounted 生命周期钩子中并不代表界面已经渲染成功,因为 mounted 不会

保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内

部使用 vm.$nextTick。

Vue 的生命周期钩子函数又分为了:单个组件生命周期、父子组件的生命周期、带缓存的路由组 件生命周期等不同的状态,在不同的状态下所拥有的生命周期内容是不相同的。 单个组件生命周期 初始化: beforeCreate created beforeMount - mounted 更新: beforeUpdate - updated 销毁: beforeDestroy destroyed 父子组件的生命周期 初始化: beforeCreate created beforeMount —child beforeCreate —child created —child beforeMount —child mounted mounted 更新: beforeUpdate —child beforeUpdate —child updated updated 销毁: beforeDestroy — child beforeDestroy — child destroyed destroyed 带缓存的路由组件生命周期 初始化: … mounted —Child activated activated 路由离开 —Child deactivated

阶段

Vue

React

小程序应

用

小程序页

面

创建 beforeCreate constructor() onLaunch onLoad created static getDerivedStateFromProps() onShow beforeMount render() onReady mounted componentDidMount() 更新 beforeUpdate static getDerivedStateFromProps() onShow onShow updated shouldComponentUpdate() onHide onHide deactivated render() activated getSnapshotBeforeUpdate() componentDidUpdate() 销毁 beforeDestroy componentWillUnmount() onUnload destroyed 捕获错 误 errorCaptured static getDerivedStateFromError() onError componentDidCatch() deactivated 路由回来 —Child activated activated 捕获子组件错误的勾子 子组件执行抛出错误 errorCaptured

19.生命周期函数能否写成箭头函数?为什么?

不能。 在 src 引入 Vue 的操作模式中,如果生命周期函数写成箭头函数形式,函数体中的 this 指向 将指向于 Window,那将无法获取到 Vue 的实例对象,也就无法操作 Vue 的特性内容。而生 命周期里面的函数(比如 setTimeout)如果写成普通函数,那么将会改变 this 指向,所以 需要写成箭头函数,以确保函数体内的 this 指向不被修改,指向于上层 Vue 实例对象内容。 在 Vue 脚手架项目的.vue 组件文件中,生命周期钩子函数如果书写成箭头函数,this 对象返 回的是 undefined,同样也无法进行 Vue 组件对象的获取。

20.哪一个生命周期钩子函数开始可以找到 this 对象内容?

哪个钩子函数开始可以找到 ref 对象?哪个钩子函数开始可

以找到 DOM 对象?

所有生命周期钩子函数都可以找到 this 对象内容,但却并不一定能够访问到想要的 this 对象 属性,在 beforeCreate 实例初始化之后调用, data 和 methods 都还没有初始化完成,通过 this 不能访问响应式数据与对应的方法内容,但因为 store、router 等对象内容是在入口文 件中进行挂载的,那么在组件的 beforeCreate 钩子函数中是通过获取到对应的对象内容的, 所以可以在 beforeCreate 钩子函数中进行类似 route 当前路由对象的参数内容获取操作。 ref 与 Dom 对象需要在 mounted 钩子函数中才能找到,而在 mounted 钩子函数中并不能 确保页面都已经被渲染成功,所以还需要利用 nextTick 来进行 DOM 对象是否最终存在,而 在 destroyed 钩子函数中因为组件的销毁,ref 以及 dom 对象内容将不再能够获取。

21.组件间的关系类型有哪几种?有哪些方式可以实现组件

之间的数据传递操作?

组件间的关系主要分成:父与子、子与父、祖与孙以及非父子之间的关系,正是因为存在组件之间 的不同关系也就意味着它们之间会存在一定的数据传递操作,而组件之间的数据传递方式主要可以 归纳为如下 10 多种实现: 父子 props:父向子、子向父 vue 自定义事件:子向父 v-model:父子之间 .sync:在父向子的基础上添加子向父 $ref,$children 与$parent $ref,$children:父向子 $parent:子向父 插槽 默认插槽/具名插槽:父组件向子组件传递标签内容 作用域插件:子向父传递数据后,父组件根据接收到的数据来决定向子组件传递不 同的标签内容 祖孙 provide 与 inject $attrs 与$listeners 非父子 全局事件总线 Vuex

22.如何访问及修改根级组件的属性?

不同于$parent、$children、$refs,$root 获取的并不是 VueComponent 组件实例,而是 Vue 实例对象,所以我们不能够直接获取到 this.$root 的 data 数据内容以及调用 this.$root 的方法 如果想要访问根级组件的数据可以利用 this.$root.$children[0].xxx的方式进行获取,利用 this.$root.$children[0]的方式可以获取根级 App 组件,因为根级组件只有一个,所以取 children 的第 1 个元素。只要组件对象获取到了,那么它的数据获取、修改以及组件方法的 调用都可以随心操作。

23.属性接收的约束以及注意事项有什么?

子组件在进行 props 属性接收的时候可以利用数组及对象的方式进行处理,但数组方式只能 进行简单的属性接收,而对像的方式则可以进行属性条件的约束操作。 利用 Object 对象进行属性条件约束时需要注意 default 默认值的设置,default 默认值在设 置时必须从一个工厂函数获取,其原因与 Vue 组件的 data 设置是一个 Function 概念是一致 的,因为需要确保数据的私有性问题。

24.Ref 的作用与指向是什么?

作用:ref 被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象 上。 指向:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素。如果用在子组件上, 引用就指向组件实例。

25.Vue 的动画方式有几种?需要注意的问题有哪些?

Vue 的动画方式主要分成两大类,一类是 CSS 动画,一类是 JS 动画 CSS 动画中包含 transition 以及 animation,但在 Vue 中只需要通过 transition 封装组件实 现。 CSS 动画的类名主要包括:v-enter、v-enter-active、v-enter-to、v-leave、v-leave- active、v-leave-to transition 只允许有一个元素内容,appear、type、duration、mode 等属性可以进行 动画操作的设置 mode 属性设置以后需要给动画元素设置唯一 key 值 in-out: 新元素先进行过渡,完成之后当前元素过渡离开。 out-in: 当前元素先进行过渡,完成之后新元素过渡进入。 一般情况下可以利用 animate.css 动画库内容进行 CSS 动画功能的实现 JS 动画仍旧操作的是 transition 组件 设置的是属性钩子,内容包括 before-enter、enter、after-enter、enter-cancelled、 before-leave、leave、after-leave、leave-cancelled 等 在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即 完成 可以设置 css 属性为 false,以免受 css 影响 js 动画同样可以利用 js 动画类库实现动画操作,比如 Velocity.js 列表动画可以利用 transition-group 进行实现

26.组件、过滤器、自定义指令的注册方式有哪几种?

组件、过滤器、自定义指令的注册方式都包含全局与局部注册两种 Vue.component、Vue.filter、Vue.directive 进行的是全局注册,需要在入口文件中进行注 册操作,所有组件可以进行使用。单词都是单数形式,需要单个内容的注册操作。 components、filters、directives 则是在当前组件中进行局部注册,只能当前组件中进行对 应功能的使用。单词形式都是复数形式,代表在组件中可以引入多个组件、过滤器与自定义 指令内容。

27.Filter 过滤器多个参数的传递以及多个过滤器的联合使

用

定义 filter 过滤器的函数第一个参数是需要过滤的对象内容,但假若在使用 filter 过滤器方法 的时候想要传递参数,那么定义的 filter 过滤器的函数参数将从第一个参数内容开始获取。 过滤器可以进行多个拼接使用,利用|管道符进行拼接,需要注意的是后面的过滤器操作的主 体是前一个过滤器操作的结果值,特别需要注意前一个过滤结果的数据类型内容,以免引起 类型操作错误。

28.Directive 自定义指令的钩子函数以及函数参数是什

么?

个指令定义对象可以提供如下几个钩子函数(均为可选):bind、inserted、update、 componentUpdated、unbind 对应钩子函数的参数主要包括:el、binding(属性:name、value、oldValue、expression、 arg、modifiers)、vnode、oldVnode

29.封装自定义插件的操作步骤主要有哪些?

Vue.js 的插件应该暴露一个 install 方法,这个方法的第一个参数是 Vue 构造器,第二个参数 是一个可选的选项对象,在这个方法中可以 添加全局方法或属性 添加全局资源 注入组件选项 添加实例方法 使用插件的时候需要 install 安装以及 use 使用操作 插件的类型主要包括: 对象插件: 调用插件对象 install 方法(传入 Vue)来安装插件(执行定义新语法的代码) 函数插件: 直接将其作为 install 来调用(传入 Vue)来安装插件(执行定义新语法的代码)

30.assets 与 static 的共性与区别是什么?

static 和 assets 的区别,原理就在于webpack 是如何处理静态资源的

static

static 目录下的文件并不会被 webpack 处理,它们会直接复制到最终目录(dist/static) 下。 必须使用绝对路径引用这些文件,这是通过在 config.js 的 build.assetsPublicPath 和 nuild.assetsSubDirectory 连接确定的。 任何放在 static/的文件需要以绝对路径形式引用:/static/[name]。 如果更改 assetsSubDirectory 的值为 assets,那么路径需更改为:/assets/[filename]。 assets 在 vue 组件中,所有模板和 css 都会被 vue-html-loader 和 css-loader 解析,并查找 资源 url。 例:或者 background: url(”./logo.png”) 因为./logo.png 是相对的资源路径,将会由 webpack 解析为模块依赖; 由于 logo.png 不是 js,当被视作模块依赖时,需要使用 url-loader 和 file-loader 处理 它,vue-cli 已经配好了这些 loader(webpack)因此可以使用相对/模块路径。 由于这些资源可能在构建过程中被内联、复制、重命名,所以它们基本是代码的一部 分,即 webpack 处理的静态资源放在/src 目录中,和其它资源文件放在一起。 总结:assets 里面的资源会被 webpack 打包进代码,static 里面的资源就直接引用了,一般在 static 里放一些类库的文件,assets 放属于项目的资源文件。

31.Vue 中如何实现表单数据的重置?

Vue 中的表单重置不像 HTML 的表单重置,只需要对 form 表单进行 reset 即可,因为 Vue 中的表单重置可能需要显示初始化的表单数据内容。 可以通过 this.$data 获取当前状态下的 data,通过 this.$options.data()获取该组件初始状 态下的 data。然后使用 Object.assign(this.$data, this.$options.data())就可以将当前状态的 data 重置为初始状态。 如果需要需要重置某个 data 的节点属性,那么可以指明对应的节点内容 Object.assign(this.$data.formSelectObj, this. $options.data())

32.本地存储的方式有哪些?各自的优势与不足是什么?

实现本地存储的方式有很多,主要包括有 localStorage、sessionStorage、indexedDb、 webSql、Cookie,它们各有优势与不足 Cookie 是最为常用的一种本地存储方式,可以设置有效期限等条件限制,但有每个域名可以 设置 50 个 Cookie,每个不超过 4K 的文件大小,不便存储敏感信息 localStorage 是一种持久化存储,没有过期时间限制,但有尺寸大小限制,它有 5M 的存储 空间 与 localStorage 相似的是 sessionStorage,不过它是会话级存储,浏览器关闭则会清除相应 的存储内容 indexedDB 是本地类似于 mongodb 一般的对象型存储方式,但对浏览器版本要求比较高, 可以进行类似 mongodb 一般的数据增、删、改、查操作,属于无限量空间存储。 webSql 也是本地数据库存储模式,同样对浏览器版本要求比较高,但它则与 mysql 关系型 数据库操作非常相似,也可以进行数据的 sql 语法操作,进行增、删、改、查,非常的方 便,也属于无限空间存储模式。

33.什么是插槽,有哪些类型?

插槽是一种组件间 html 传递的策略,实现父组件向子组件传递标签内容。插槽的类型主要包括: 普通插槽、具名插槽以及作用域插槽 对于作用域插槽是在父组件需要向子组件传递标签结构内容,但决定父组件传递怎样标签结构的数 据是在子组件中。在 Vue2.6 版本以后,新版本插槽的语法比起老版本区别略有区别,主要可以利 用#slotName={property}的方式进行简化缩写。

34.组件的类型及特点有哪些?

如果想要对组件进行类型划分,从实现的功能以及所具备的特点来划分,大致可以归纳为:动态组 件、缓存组件、异步组件、函数式组件 + JSX、递归组件等 动态组件:通过动态确定要显示的组件, is 指定要显示组件的组件名 问题: 当从 A 组件切换到 B 组件时, A 组件就会销毁 缓存组件:即可以利用 component,也可以使用 router-view 使用缓存动态组件, 可以通过 include 或 exclude 指定只缓存特定组件

slot="插槽的名字" + slot-scope="{要收集的数据-1,要收集的数据-2}"
=
v-slot:插槽名字="{要收集的数据-1,要收集的数据-2}"
=

#插槽名字=“{要收集的数据-1,要收集的数据-2}”

<component :is="currentComp"/>

使用也可以缓存路由组件 路由组件对象什么时候创建? 默认: 每次跳转/访问对应的路由路径时 有缓存: 第一次访问时 路由组件对象什么时候死亡? 默认: 离开时 有缓存: 离开时不死亡, 只有当 destroy/父组件死亡/刷新页面 异步组件 好处:能更快的看到当前需要展现的组件界面(异步组件的代码开始没有加载) 无论是路由组件还是非路由组件都可以实现异步组件效果 拆分单独打包 需要时才请求加载组件对应的打包文件 配置组件: component: () => import(modulePath) import(modulePath): 被引入的模块会被单独打包(code split) —ES8 的新语法 () => import(modulePath): 函数开始不调用, 当第一次需要显示对应的界面时才会 执行, 请求加载打包文件 细节 import()返回 promise, promise 成功的结果就是整体模块对象 本质上: 可以利用 import()实现对任意模块的懒加载 函数式组件 + JSX,与 Vue 的 Component 概念有明显不同,更雷同于 React 中的函数式组 件 只能针对无状态(data)的组件 不用创建实例对象, 运行更快 可以没有根标签 递归组件,组件内部有自己的子组件标签,简单的说就是组件自已调用自身 应用场景: 用于显示树状态结构的界面 注意: 递归组件必须有 name

35.简述一下对 Vue-Router 的理解?

<keep-alive :exclude="['Home']">
<component :is="currentComp"/>
</keep-alive>
<keep-aliveinclude='Life1'>
<router-view></router-view>
</keep-alive>
exportdefault {
functional: true, // 当前是函数组件
render(createElement, context) {
return要显示界面的虚拟DOM;
},
};

功能

React-router

Vue-Router

静态路由 表及分配 地址 HashRouter/BrowserRouter as Router Route/Switch 设置数组,path 和 component 对象 内容的确认 首页的渲 染 Route 的 path 为/,但是需要加上 exact router-view 链接形式 1 a 链接,但是要加# a 链接,但是要加# 链接形式 2 Link/NavLink 链接,to,不需要加# router-link,to,不需要加# 高亮显示 NavLink 下的 activeClassName/activeStyle active-class 路由嵌套 是通过不同的组件中设置 Route 来 进行路由的嵌套,嵌套操作被拆分了 children 嵌套 路由嵌套 的显示 Route 既是路由,也是占位渲染显示 router-view 参数传递 设参在路由 :xxx 传参在地址 Link/NavLink to 的设置接参在组件 this.props.match.params.xxx 设参在路由 :xxx 传参在地址 router- link 的 to 的设置接参在组件 this.$route.params.xxx/watch 首页的高 亮显示 exact exact 多层嵌套 是通过不同的组件中设置 Route 来 进行路由的嵌套,嵌套操作被拆分了 children 的多层嵌套+router-view 程序式导 航 this.props.history.push(pathUrl) this.$router.push(pathUrl) Miss 与 NoMatch NoMatch 不需要写 path,直接写 NoMatch redirect 与*号通配符 在以往的项目开发中,包括使用不同技术栈的项目内容,例如 nodejs 的 express、Vue 项目、 React 项目、小程序项目等都涉及到了路由的概念与操作。虽然这些项目归属于不同的技术体系, 但路由的核心概念都是一致的,我也做了相应的归纳,总结出 5 个词进行了概括:静态路由表、 分配地址、统一入口、寻址渲染,过滤判断。当然,对于不同的技术体系,路由的表现与配置方式 会有所差异与不同。 路由的具体操作又表现在:操作模式、跳转方式、参数的传递、嵌套处理、守卫管理、懒加载及动 态路由等方面。

36.路由守卫的类型有哪些,一共有几个路由守卫,不同类

型包含哪些路由守卫的钩子函数

导航守卫是什么? 导航守卫是 vue-router 提供的下面 2 个方面的功能 监视路由跳转 —>回调函数 控制路由跳转 —> 放行/不放行/强制跳转到指定位置 next() 应用 在跳转到界面前, 进行用户权限检查限制(如是否已登陆/是否有访问路由权限) 在跳转到登陆界面前, 判断用户没有登陆才显示 导航守卫分类主要包括: 全局守卫:beforeEach、beforeResolve、afterEach 路由独享的守卫:beforeEnter 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave 当点击切换路由时:beforeRouterLeave—>beforeEach—>beforeEnter—>beforeRouteEnter—

beforeResolve—>afterEach—>beforeCreate—>created—>beforeMount—>mounted— beforeRouteEnter 的 next 的回调 当路由更新时:beforeRouteUpdate

37.最为常用的路由守卫类型是哪个,主要应用在什么功能

操作?

最为常用的路由守卫应当是全局守卫中的 beforeEach,因为在用户权限认证操作过程中都会需要 该守卫操作的处理,而用户权限又是每个项目中不可缺少的一部分。 关键技术: 全局前置守卫 beforEach + 动态添加路由 判断是否有 token 没有 token, 判断请求是否是白名单路由: 是: 直接放行 不是: 强制跳转到 login 页面 有 token, 判断请求的是否是 login 页面 是: 强制跳转到根路由 不是, 判断是否已经登陆? 已登陆: 放行 没有登陆: 请求获取用户相关信息数据: name/avatar/路由的权限数据和按钮的权 限数据 请求成功了: 将用户相关数据保存到 vuex 中 根据路由权限数据动态生成权限路由的数组 将所有的权限路由和匹配任意路由的路由动态添加到 router 中 请求失败了: 删除 cookie 中和 token 删除 vuex 中用户相关信息 强制跳转到登陆页面

38.router 与 route 的差异与区别是什么?

我们可以根据这两个单词的长度来进行判断,一个是 router,这个单词长一些,代表的是整 个路由对象,里面是整个静态路由表的配置信息。如果需要实现路由的跳转,则需要从整个 静态路由表对象中进行匹配,所以使用的是 router。 而 route 这个单词短一些,代表的是当前的路由页面内容,如果需要获取当前路由对象的参 数信息,则可以对 route 内容进行处理。

39.Vue 的双向数据绑定原理是什么?

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

40.对 keep-alive 的了解

keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。它有两个 属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于 include) 。 使用方法 参数解释 include - 字符串或正则表达式,只有名称匹配的组件会被缓存 exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存 include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、 数组。当使用正则或者是数组时,要记得使用 v-bind 。 使用示例

<keep-aliveinclude="include_components"exclude="exclude_components">
<component>
<!-- 该组件是否缓存取决于include和exclude属性 -->
</component>
</keep-alive>
<keep-aliveinclude="a,b">
<component></component>
</keep-alive>
<keep-alive:include="/a|b/">
<component></component>
</keep-alive>
<!-- Array (需要使用 v-bind,被包含的都会被缓存) -->

内容

作用

映射

位置

调用

其它

state 设置状 态 mapState computed getters 获取内 容 mapGetters computed 计算数据后返回 mutations 修改数 据 mapMutations methods commit 可以异步但不建 议,不利调试 actions 异步操 作 mapActions methods dispatch modules 模块拆 分 namespaced plugins 插件辅 助

41.路由切换以后需要进行页面中某一锚点的定位需要如何

实现?

需要利用 router 的 scrollBehavior 来进行指定位置的跳转操作

42.你如何理解 vuex?

vuex 的 6 大属性:

43.vuex 中的 namespaces 是什么?它的主要作用是什

么?

在 Vuex 模块中开启 namespaced 以后,确定该模块为带命名空间的模块。当模块被注册后,它 的所有 state、getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

44.如何解决 vuex 数据丢失问题?

刷新页面 Vuex 的 state 会丢失,可以利用 vuex-persist、vuex-persistedstate 状态持久化插件将 state 数据存储于本地存储对象当中,比如 localStorage。

45.vuex 和 redux 的区别?

<keep-alive:include="['a', 'b']">
<component></component>
</keep-alive>
scrollBehavior: function (to) {
if (to.hash) {
return {
selector: to.hash
}
}
},

vuex: 我们直接在 mutation 中直接更新状态数据 直接可以在 action 中执行异步操作 redux: 只能通过 reducer 返回一个新的状态数据, 由 redux 内部自己更新 本身不支持异步, 必须引入 react-redux 之类的插件才支持异步 ::: danger 虚拟滚动列表 虚拟滚动列表的实现原理是什么?(详见:虚拟滚动列表.html 示例) :::

46.如果不使用分页处理,在一个页面中想显示 10 万条数

据,如何实现高效的 DOM 渲染处理?

利用虚拟滚动的方式,控制在指定区域内容只渲染可显示范围的数据内容,不增加 DOM 节 点 vue-virtual-scroller/vue-virtual-scroll-list 第三方插件的应用

47.前端开发人员在不借助后端人员协助的情况下,如果换

作是你,如何最快速的实现跨域问题的解决?跨域问题的解

决一般有哪些方式,如何实现?

直接安装 Chorme 插件,CORS unblock 开启插件即可 利用 vue.config.js 配置 devServer 的 proxy 反向代理 通过建立本地 nginx 服务器,配置代理地址

48.一般情况,你会对程序的错误分成几大类型?你是如何

进行程序的调试的处理的?

语法错误:利用编辑器进行提示,包括 eslint 等辅助工具的配置使用 运行错误:利用报错提示查看出错的行列,分析错误情况进行排错 逻辑错误:梳理业务流程,利用 debug 调试工具,包括断点测试实现纠错

49.你如何快速了解、学习与掌握脚手架项目或者其他公司

新接收的项目?

项目的发解、学习与掌握也是有一定的顺序与方法的,主要的流程包括如下几个步骤: 有 Readme 说明文档一定先看 Readme 说明文档,最为主要解决的是项目运行环境的搭建 与启动 项目目录结构的分析 项目文件结构的分析 项目代码结构的分析:需要找到入口文件以及主组件,从入口文件着手,主组件触发,从上 到下,剥洋葱一般的进行代码层次结构的剥离与分析

50.对于 Vue 项目,你所常用的性能优化方式主要包含哪些

方面?

项目性能优化的方面包含很多,针对 Vue 项目的优化可以介绍几种类型的内容,主要包括:Vue 代码层面的优化、webpack 配置层面的优化、基础的 Web 技术层面的优化、用户体验优化等 代码层面的优化: v-if 和 v-show computed 和 watch 不要将所有的数据放在 data 中,固定数据或者定时器等可设置于实例对象当中 keep-alive 缓存组件 v-for 遍历 key 设置,且避免同时使用 v-if 长列表利用 Object.freeze 冻结数据 监听对象的销毁 图片资源懒加载 路由懒加载,异步组件 第三方插件的按需引入 无限列表利用虚拟滚动列表实现 服务端渲染或预渲染 函数式组件应用 高频触发使用防抖、节流 事件委托 图片编码优化,尽量使用 svg 和字体图标 避免重定向以及 404 页面 动态注册组件 使用编程式导航代替声明式导航 前端表单验证,减少请求处理 Webpack 层面的优化 文件压缩,包括图片、css、js、html 等 减少 ES6 转为 ES5 的冗余代码 提取公共代码 模板预编译 模块文件的提取,包括 css、第三方 js 库等 优化 SourceMap 构建结果输出分析 基础的 Web 技术层面的优化 开启 gzip 压缩 浏览器缓存 CDN 的使用 使用 Chrome Performance 查找性能瓶颈 https://www.jianshu.com/p/ef44aaa41fe8

51.路由跳转指定 params 参数时可不可以用 path 和

params 配置的组合?

不可以,只能用 name 和 params 配置的组合,query 配置可以与 path 或 name 进行组合使用

52.如何指定 params 参数可传可不传?

path: ‘/search/:keyword?’,利用?号设定

53.如果指定 name 与 params 配置, 但 params 中数据是

一个"", 无法跳转

不指定 params 或者指定 params 参数值为 undefined

54.路由组件能不能传递 props 数据?

可以:可以将 query 或 params 参数映射成 props 传递给路由组件对象

55.编程式路由跳转到当前路由(参数不变), 会抛出

面试问题::在做项目时有没有遇到比较难的问题?(可做回答) 回答步骤:

  1. 我的问题: 我在上一个项目时没有问题,后面再做一个新的项目时就有了问题
  2. 原因分析: vue-router3.1.0 之后,引入了 push()的 promise 的语法,如果没有通过参数指定 回调函数就返回一个 promise 来指定成功/失败的回调,且内部会判断如果要跳转的路径和 参数都没有变化,会抛出一个失败的 promise
  3. 解决办法:解决 1: 在跳转时指定成功或失败的回调函数, 通过 catch 处理错误 解决 2: 修正 Vue 原型上的 push 和 replace 方法 (优秀) 56.是否有对 axios 进行二次封装?主要的封装功能包括哪些?
  4. 配置通用的基础路径和超时: axios.create({baseURL, timeout})
  5. 显示请求进度条 显示: 准备发请求前显示, 在请求拦截器中执行 NProgress.start() 隐藏: 请求结束隐藏, 在响应拦截器成功/失败回调中 NProgress.done()
  6. 携带 token 数据 在请求拦截器中, 将 token 添加到请求头中
  7. 成功返回的数据不再是 response, 而直接是响应体数据 response.data
//在routes中配置
props: (route) => ({ keyword1: route.params.keyword, keyword2:
route.query.keyword });

// 缓存原型上的push方法

constoriginPush=VueRouter.prototype.push;
VueRouter.prototype.push=function(location, onComplete, onAbort) {
console.log('push()', location, onComplete, onAbort);
// this是路由器对象 $router

// 如果调用push, 传递了成功或者失败的回调函数

if (onComplete||onAbort) {

// 让原来的push方法进行处理

originPush.call(this, location, onComplete, onAbort); // 不用返

回, 因为执行的结果返回是undfined

} else {

// 如果调用push, 没传递了成功或者失败的回调函数, 可能会抛出失败的promise,

需要catch一下
returnoriginPush.call(this, location).catch(() => {
console.log('catch error');
}); // 必须返回产生的promise对象
}
};

响应拦截器成功的回调中: return response.data 5. 统一处理请求错误, 具体请求也可以选择处理或不处理 在响应拦截器失败的回调中: alert 提示错误信息, return Promise.reject(error)

56.为什么要使用编程式导航代替声明式导航,典型应用场

景是什么?

在重复使用声明式导航时需用编程式导航替换,以便提升性能。在电商项目商品分类跳转时可以进 行编程式导航的应用。

57.如何配置使用 swiper?

必须在列表显示显示之后创建 , 在 mounted()中创建 异步动态获取数据并且在 mounted 中创建 Swiper 对象也会导致没有轮播效果,需要 nextTick 确定 DOM 已经渲染完毕

58.如何解决多个 swiper 效果冲突的问题

问题: 针对某个 swiper 界面创建一个 swiper 对象, 它会影响了其它界面的 swiper 界面 原因: new Swiper (‘.swiper-container’), 类名选择器匹配了页面中所有的 swiper 界面, 都产 生了效果 解决: 使用 ref 技术: 通过 ref 标识 swiper 的根 div, new Swiper (this.$refs.swiper)

59.什么情况下需要深度作用选择器修改第三方 UI 组件的内

部样式,如何实现

场景:当我们需要覆盖 element-ui 等 UI 框架中组件的样式时可以通过深度作用选择器

style 为 css 时的写法如下

style 使用 css 的预处理器(less, sass, scss)的写法如下

60.利用深拷贝解决修改不能取消的问题

在对某数据进行修改时考虑还需要进行“确认”、“取消”操作,那么在取消时就需要返回保留的数据 内容,那么如何将原有数据保留一份则是关键性问题。 显然修改值不能直接进行原值的赋值操作,因为这样无法取消回退

.a >>> .b {
...;
}
/deep/ .a {
...;
}
/* /deep/在某些时候会报错,::v-deep更保险并且编译速度更快 */
::v-deep.a {
...;
}

如果采用浅拷贝,那么浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还 是共享同一块内存,那么数据还是会出现问题 需要采用深拷贝的形式进行数据的复制 JSON.parse(JSON.stringify(obj))实现深拷贝其实会存在很多的问题 如果 obj 里面有时间对象,则 JSON.stringify 后再 JSON.parse 的结果,时间将只 是字符串的形式,而不是时间对象 如果 obj 里有 RegExp、Error 对象,则序列化的结果将只得到空对象 如果 obj 里有函数,undefined,则序列化的结果会把函数或 undefined 丢失 如果 obj 里有 NaN、Infinity 和-Infinity,则序列化的结果会变成 null JSON.stringify()只能序列化对象的可枚举的自有属性,例如如果 obj 中的对象是 有构造函数生成的,则使用 JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对 象的 constructor 如果对象中存在循环引用的情况也无法正确实现深拷贝 使用 lodash 的 cloneDeep 进行数据的深拷贝

61.vue 变量名如果以_、$开头的属性会发生什么问题?怎

么访问到它们的值?

以_或者$开头的属性不会被 vue 实例代理,因为它们可能会和 vue 内置属性、api 方法冲突 可以使用 vm.$data._property 的方式访问这些属性。

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

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

63.Vue 渲染模板时怎么保留模板中的 HTML 注释呢?

64.如何更优雅的进行监听对象的清除处理?

可以通过$once 这个事件侦听器在定义完定时器之后的位置来清除定时器

65.请说一下 computed 中的 getter 和 setter

computed 中可以分成 getter(读取)和 setter(设值),一般情况下是没有 setter 的, computed 预设只有 getter,也就是只能读取,不能改变设值。

// 模板标签添加 comments 属性
<templatecomments>
...
</template>
mounted(){
consttimer=setInterval(()=>{
console.log(1)
},1000)
this.$once('hook:beforeDestroy',()=>{ // 监听beforeDestroy这个钩子函数
clearInterval(timer)
})
}

默认只有 getter 的写法 注意:不是说我们更改了 getter 里使用的变量,就会触发 computed 的更新,前提是 computed 里的值必须要在模板里使用才行。如果将{{fullName}}去掉,get()方法是不会 触发的。 setter 的写法,可以设值

<divid="demo">{{ fullName }}</div>
varvm=newVue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
returnthis.firstName+' '+this.lastName
}
}
})

//其实fullName的完整写法应该是如下:

fullName: {
get(){
returnthis.firstName+' '+this.lastName
}
}
<template>
<divid="demo">
<p> {{ fullName }} </p>
<inputtype="text"v-model="fullName">
<inputtype="text"v-model="firstName">
<inputtype="text"v-model="lastName">
</div>
</template>
varvm=newVue({
el: '#demo',
data: {
firstName: 'zhang',
lastName: 'san'
},
computed: {
fullName: {
//getter 方法
get(){
console.log('computed getter...')
returnthis.firstName+' '+this.lastName
},
//setter 方法
set(newValue){
console.log('computed setter...')
varnames=newValue.split(' ')
this.firstName=names[0]
this.lastName=names[names.length-1]
returnthis.firstName+' '+this.lastName

在这里,我们修改 fullName 的值,就会触发 setter,同时也会触发 getter。 注意:并不是触发了 setter 也就会触发 getter,他们两个是相互独立的。我们这里修改了 fullName 会触发 getter 是因为 setter 函数里有改变 firstName 和 lastName 值的代码,这 两个值改变了,fullName 依赖于这两个值,所以便会自动改变。

66.如果 elementUI,iview 等 UI 框架的 Table 表格组件

功能达不到业务复杂度需求,比如需要实现树形结构的深度

查询、分组汇总以及合计、行列单元格的可编辑操作等,会

如何操作?

elementUI,iview 是比较符合大众业务需求的 UI 框架,而表格组件在业务需求的使用中极为的频 繁,elementUI,iview 对于 Table 表格组件的功能并没有做极大的强化,所以可以考虑选择更为 专业的 vxe-table 插件,https://xuliangzhan_admin.gitee.io/vxe-table/#/table/start/install

67.利用 Vue 技术体系是否能够进行小程序项目的开发?

可以 wepay、mpx、mpvue(停更)、uniApp 都是类 Vue 或者是 Vue 体系的技术框架,利用它 们可以进行小程序项目的开发。

68.利用 Vue 技术体系是否能够进行 App 项目的开发?

可以 阿里的 weex,dclould 的 uniApp,还有 NativeScript 的 Vue 体系都可以进行移动端 App 项目的开发。

69.如何实现路由参数的响应式处理?

可以利用监控或者组件的路由守卫功能实现 监控模式: 路由守卫模式:

}
}
}
})
constUser= {
template: '<div>User {{ $route.params.name }} </div>',
watch: {
$route(to, from) {
// react to route changes...
},
},
};

70.在同一组件中能否既定义全局样式,又定义组件局部样

式?

可以,定义两个 style,一个没有 scoped,一个有 scoped

71.Vue 中多国语言支持需要利用什么方式实现?

可以利用 Vue-i18n 插件实现:http://kazupon.github.io/vue-i18n/

72.能否将 vue-router 当前的 $route 同步为 vuex 状态的

一部分?

可以,利用 vuex-router-sync 可以将 vuex 与 router 对象进行同步,将当前的$route 同步为 vuex 状态的一部分,我们甚至可以利用修改 vuex 的路由状态来进行路由地址的跳转与参数传递

73.如何对 lodash 库实现按需引入

74.如何实现跨域配置

在 vue.config.js 中对 devServer 进行属性配置

75.理解 Vue.use

自定义 Vue 插件需要向外暴露对象或者是函数 如果向外暴露对象的话,对象中必须有 install 方法 如果向外暴露的是函数的话,那么该函数本身就是 install 方法 当 Vue.use()的时候,会自动调用 install 方法,并且将 Vue 对象作为实参传入到 install 方法 中

constUser= {
template: '<div>User {{ $route.params.name }} </div>',
beforeRouteUpdate(to, from, next) {
// react to route changes and then call next()
},
};
commit('route/ROUTE_CHANGED', { to: { path: '/b' } });
import_from'lodash'; // 引入整体lodash  ==> 打包了没用的工具函数, 打包文件变大
importthrottlefrom'lodash/throttle'; // 只引入我需要的工具函数   打包文件减少
1.4M
proxy: {
'/dev-api': { // 匹配所有以 '/dev-api'开头的请求路径
target: 'http://182.92.128.115', // 代理目标的基础路径
changeOrigin: true, // 支持跨域
pathRewrite: { // 重写路径: 去掉路径中开头的'/dev-api'
'^/dev-api': ''
}
},
}

75.history 模式刷新 404 问题解决方法

通过配置 webpack 来解决:在 devServer 中加 historyApiFallback: true index.html 需要将 href=”./bootstrap.css” 等内容改成 href=“/bootstrap.css” webpack.config.js 需要 output 上增加 publicPath: ’/‘

76.v-model 都做了哪些事情

将指定变量的数据赋值给 input 的 value 给当前的表单相自动绑定一个 input 事件,监听 View 层表单项数据发生改变获取最新 value 的同时更新 Model 的数据

77.路由设置中的 meta 属性通常设置什么内容?

一般我们会设置 title 标题以及 isAuth 是否授权操作等自定义的路由属性内容

78.如何动态修改 Vue 单页面应用的标题

通过设置路由的 meta 属性,添加路由 title 标题 利用路由全局守卫可以进行拦截并修改标题设置

79.什么是 Props 传递数据防脏

所有的 props 都使得其父子组件形成一个单向下行绑定,父级 props 的更新会流动到子组件中, 但反过来不行。这种设计办法是为了防止子组件意外改变父组件的状态,从而导致你的应用的数据 流向难以理解。另外,如果该数据还被其他子组件使用,也将受影响,产生洪水式灾难。因此不应 该在子组件中设计修改 props 数据的操作。

80.如何实现数据防脏操作?

利用 update:myPropName 的方式进行数据防脏处理 子组件赋值操作 父组件事件绑定处理 缩写模式,利用 sync

81.你所熟悉与应用的 VueUI 框架有哪些?

PC 端主要有 iview、elementUI、Ant-Design-Vue

router.beforeEach= ((to,from,next)) => {
window.document.title=to.meta.title;
next();
});
this.$emit('update:title', newTitle);
<text-documentv-bind:title="doc.title"v-on:update:title="doc.title =
$event"></text-document>
<text-documentv-bind:title.sync="doc.title"></text-document>

移动端:MintUI、Vant、Vux

82.如果实现 css 的模块化?

使用 CSS Modules 实现样式的模块化

83.如何实现事件委托操作?

利用事件冒泡将事件操作委托于父元素的事件对象内容

84.如何实现模块自动化加载操作?

require.context()函数获取一个特定的上下文,主要用来实现自动化导入模块,在前端工程中,如 果遇到从一个文件夹引入很多模块的情况,可以使用这个 api,它会遍历文件夹中的指定文件,然后自 动导入,使得不需要每次显式的调用 import 导入模块

<!-- 使用CSSModules-->
<stylemodule>
.button {
border: none;
border-radius: 2px;
}
.buttonClose {
background-color: red;
}
</style>
<!-- 不将事件绑定于button,而是绑定在table上 -->
<table@click="edit">
<trv-for="item in list":key="item.id">
<td>{{ item.name }}</td>
<td>
<button:data-id="item.id"title="edit">编辑</button>
</td>
</tr>
</table>

// 通过获取绑定的标识参数来确认事件目标对象

edit(event) {
if (event.target.title=="edit") {
//如果点击到了edit
letid=event.target.dataset.id;
}
},

85.addRoutes 的作用与应用场景

addRoutes 可以实现动态路由的添加操作 应用场景:根据用户权限判断展示不同路由菜单项 前台公共路由的获取 后台通过用户权限判断返回具体用户拥有的路由 前台利用 addRoutes 将公共路由与后台返回的动态路由进行组合成新的用户功能路由

86.不同路由同一组件的重用

如果设置不同的路由,但指向的是同一组件,那么因为组件性能考虑及缓存策略,组件并不会刷 新,那么如何实现组件的刷新重用呢?

87.如何实现组件属性的验证处理?

可以利用 validator 进行自定义验证方法的定义处理

88.如何实现组件的刷新?

一般情况组件的 state 状态或者是 props 发生改变时就会进行刷新渲染,但有时需要进行用户控 制,那么有哪些方法呢: 最差的方式:刷新页面 常见的方法:v-if 控制组件的显示 利用 forceUpdate 强制更新,将触发 updated 钩子函数

/*
动态加载vuex中所有的modules模块

不再需要通过import手动一个一个引入

*/
constcontext=require.context('./modules', false, /\.js$/);
constmodules=context.keys().reduce((modules, modulePath) => {
// './app.js' => 'app'
constmoduleName=modulePath.replace(/^\.\/(.*)\.\w+$/, '$1');
modules[moduleName] =context(modulePath).default;
returnmodules;
}, {});
router.addRoutes([...asyncRoutes, lastRoute]);
<template>
<router-view:key="$route.fullPath"></router-view>
</template>
alertType: {
validator: (value) => ['signup', 'login', 'logout'].includes(value);
}
<template>
<divid="app">
<h1>{{ Math.random() }}</h1>
<button@click="update">Force Update</button>

利用 mount 进行重新挂载,将触发 beforeMount 与 updated 钩子函数

89.重载刷新页面

this.$router.go(0) 相当于 F5 刷新,这种方法虽然代码很少,只有一行,但是体验很差。页 面会一瞬间的白屏,体验不是很好 location.reload() 这种也是一样,画面一闪,体验不是很好,相当于页面刷新 推荐解决方法:用 provide / inject 组合 在 App.vue,声明 reload 方法,控制 router-view 的显示或隐藏,从而控制页面的再次加载。

</div>
</template>
<script>
exportdefault {
methods: {
update() {
this.$forceUpdate();
},
},
};
</script>
<divid="app">
<h1>{{Math.random()}}</h1>
<button@click="update">Force Update</button>
</div>
</template>
<script>
exportdefault {
methods:{
update(){
this.$mount();
}
}
};
</script>
<template>
<divid="app">
<router-viewv-if="isRouterAlive"></router-view>
</div>
</template>
<script>
exportdefault {
name: 'App',
provide() {
return {
reload: this.reload,
};
},
data() {
return {

在需要用到刷新的页面。在页面注入 App.vue 组件提供(provide)的 reload 依赖,在逻辑完成 之后(删除或添加…),直接 this.reload()调用,即可刷新当前页面。 注入 reload 方法 在需要重载的地方直接调用

90.表单提交时如何阻止页面刷新?

表单提交时为了防止页面刷新需要进行默认事件的阻止处理,可以利用 submit.prevent 进行实 现。

91.是否有集成过在线编辑器?使用的是哪些?

百度 ueditor 的 Vue 版本,vue-ueditor-wrap,功能强大,配置略麻烦:https://github.com/Ha oChuan9421/vue-ueditor-wrap quill-editor 的 Vue 版本,vue-quill-editor,功能一般,配置简单:https://github.com/surmon- china/vue-quill-editor

92.是否有了解过动态表单生成概念?

所谓的动态表单就是根据数据库动态获取的字段配置信息生成表单模块,这一操作在产品的 SKU 管理,还有 OA,ERP 系统中应用广泛。 vue-form-generator:https://github.com/vue-generators/vue-form-generator vue-dynamic-form-component:https://vue-dynamic-form.quincychen.cn/

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

比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处 理,可以通过以下写法实现:

isRouterAlive: true,
};
},
methods: {
reload() {
this.isRouterAlive=false;
this.$nextTick(function() {
this.isRouterAlive=true;
});
},
},
};
</script>
exportdefault {
inject: ['reload'],
};
this.reload();

以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 来监听即可,如下所示: 当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。

94.首屏加载性能优化中为了解决 js 阻塞需要实现库文件的

抽离,如何实现?

修改 vue.config.js 配置,configureWebpack 属性中加入 externals,将对应的类库抽离,需要在 index.html 中加入对应的 cdn 文件。

95.首屏性能优化一般有哪些方案?

异步路由加载 不打包库文件 关闭 sourcemap 开启 gzip 压缩 单独 SSR 页面生成

96.什么是 XSRF 攻击,Vue 中如何做好相应的安全策略?

Cross-site request forgery 跨站请求伪造,也被称为“One Click Attack”或者 Session Riding,通 常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。CSRF 定义的主语是”请求“,是一种跨站的 伪造的请求,指的是跨站伪造用户的请求,模拟用户的操作。

// Parent.vue
<Child@mounted="doSomething"/>
// Child.vue mounted() { this.$emit("mounted"); } 复制代码
// Parent.vue
<Child@hook:mounted="doSomething"></Child>
doSomething() { console.log('父组件监听到 mounted 钩子函数 ...'); }, //
Child.vue mounted(){ console.log('子组件触发
mounted 钩子函数 ...'); }, // 以上输出顺序为: // 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...

复制代码

module.exports ={
publicPath:'./',
configureWebpack:{
// 此处可以配置 cdn 配置
// 需要在index.html 中引入 cdn 文件
externals:{
vue:'Vue',
'vue-router':'VueRouter',
vuex:'vue',
'element-ui':'ELEMENT'
}
}
}

在 Vue 中进行 vue-csrf 插件的使用:https://github.com/nicita13/vue-csrf

97.电商平台购物车流程的处理方式有哪几种,操作流程与

优势不足各有哪些

购物车数据本地缓存存储模式,单设备存储与应用,切换设备将无法同步,但性能优良 以 id 为参数模式的操作方式 用户查看产品详情,将产品添加到购物车,而购物车中生成的是一个单一数组,类 似[1,2,1,1,3,4,4] 1,2,3,4 为产品 id,出现的次数为购买的数量 在购物车清单页面需要进行再次的数据请求与查询 选中购物车产品等操作则增加程序复杂层度 以对象为参数模式的操作方式 用户查看产品详情,将产品添加到购物车,而购物车中生成的是一个对象数组,将 会把产品整体对象传递并存储于数组当中 可以给数组对象添加 count(购买数量),selected(是否选中)等属性值 在购物车清单页面不再需要进行数据请求与查询操作,减少性能开销 选中购物车产品等操作简化程序复杂层度 购物车数据远程序服务器存储模式,与本地设备无关,切换设备也可以同步数据,请求次数 多,服务器压力大,性能略低下 将用户信息、产品 id 以及购买数量等信息作为参数进行订单接口的请求操作 由服务器端进行订单内容的查询、新增、更新与删除的操作 订单列表页则需要进行订单列表接口的请求获取与显示操作 每个商品信息任何一次变化都需要与后台接口进行交互,http 请求次数巨大

98.什么是 SPU、什么是 SKU?

SPU = Standard Product Unit (标准化产品单元) SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一 个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个 SPU。 SKU=stock keeping unit(库存量单位) SKU 即库存进出计量的单位,可以是以件、盒、托盘等为单位。 SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。在服 装、鞋类商品中使用最多最普遍。

99.Vue 中项目中,你有了解哪些 SKU 的表单生成插件?

vue-sku:基于 element-ui 实现 zent sku 商品规格组件。https://github.com/easeava/vue-sku vue-sku-form:基于 Vue & ElementUI 的电商 SKU 表单配置组件。https://hooray.github.io/vu e-sku-form/

100.Vuex 中命名空间使用后组件调用带命名空间的

action 方法里有几种方式?

直接利用 store 进行单个调用:this.$store.dispatch(‘moduleName/run’, command); 利用 mapActions 映射,空间模块直接映射方式

mapActions(['some/nested/module/foo', 'some/nested/module/bar']);

空间模块调用方式: 利用 mapActions 映射,空间模块名称+方法数组方式 空间模块调用方式:

附加知识点面试题

一、jQuery 选择器:

1、基本选择器

2、层级选择器

3、过滤选择器

this['some/nested/module/foo']();
this['some/nested/module/bar']();
...mapActions('some/nested/module', [
'foo',
'bar'
])
// -> this.foo()
// -> this.bar()
#id            根据给定的ID匹配一个元素

element       根据给定的元素标签名匹配所有元素

.class         根据给定的css类名匹配元素。
*              匹配所有元素
selector1,selector2,selectorN    将每一个选择器匹配到的元素合并后一起返回
ancestordescendant    在给定的祖先元素下匹配所有的后代元素
parent>child           在给定的父元素下匹配所有的子元素
prev+next              匹配紧接在prev元素后的next元素
prev~siblings          匹配prev元素之后的所有siblings元素
:first             获取第一个元素
:not(selector)     去除所有与给定选择器匹配的元素
:even              匹配所有索引值为偶数的元素,从0开始计数
:odd               匹配所有索引值为奇数的元素,从0开始计数
:eq(index)         匹配一个给定索引值的元素
:gt(index)         匹配所有大于给定索引值的元素
:lang              选择指定语言的所有元素。1.9+
:last              获取最后个元素
:lt(index)         匹配所有小于给定索引值的元素
:header            匹配如h1, h2, h3之类的标题元素
:animated          匹配所有正在执行动画效果的元素
:focus             匹配当前获取焦点的元素
:root              选择该文档的根元素   1.9+

4、内容选择器

5、可见性选择器

6、属性选择器

7、子元素选择器

8、表单选择器

:target            选择由文档URI的格式化识别码表示的目标元素    1.9
:contains(text)    匹配包含给定文本的元素
:empty             匹配所有不包含子元素或者文本的空元素
:has(selector)     匹配含有选择器所匹配的元素的元素
:parent            匹配含有子元素或者文本的元素
:hidden        匹配所有不可见元素,或者type为hidden的元素
:visible       匹配所有的可见元素
[attribute]            匹配包含给定属性的元素
[attribute=value]      匹配给定的属性是某个特定值的元素

[attribute!=value]     匹配所有不含有指定的属性,或者属性不等于特定值的元素

[attribute^=value]     匹配给定的属性是以某些值开始的元素
[attribute$=value]     匹配给定的属性是以某些值结尾的元素
[attribute*=value]     匹配给定的属性是以包含某些值的元素
[attrSel1][attrSel2][attrSelN]    复合属性选择器,需要同时满足多个条件时使用
:first-child        匹配所给选择器( :之前的选择器)的第一个子元素
:first-of-type      结构化伪类,匹配E的父元素的第一个E类型的孩子        1.9+
:last-child         匹配最后一个子元素
:last-of-type       结构化伪类,匹配E的父元素的最后一个E类型的孩子    1.9+
:nth-child()        匹配其父元素下的第N个子或奇偶元素

:nth-last-child()   选择所有他们父元素的第n个子元素。计数从最后一个元素开始到第一个    1.9+ :nth-last-of-type() 选择的所有他们的父级元素的第n个子元素,计数从最后一个元素到第一个

1.9+
:nth-of-type()      选择同属于一个父元素之下,并且标签名相同的子元素中的第n个    1.9+

:only-child         如果某个元素是父元素中唯一的子元素,那将会被匹配

:only-of-type       选择所有没有兄弟元素,且具有相同的元素名称的元素    1.9+
:input           匹配所有input, textarea, select和button元素
:text            匹配所有的单行文本框
:password        匹配所有密码框
:radio           匹配所有单选按钮
:checkbox        匹配所有复选框
:submit          匹配所有提交按钮,匹配type="submit"的input或者button
:image           匹配所有图像域
:reset           匹配所有重置按钮
:button          匹配所有按钮
:file            匹配所有文件域

9、表单对象选择器

10、混淆选择器

二、ES5与ES6的类的继承,以及ES5继承方式有哪些?

ES5中:

1、原型链继承

原型链继承的核心:将父类的实例作为子类的原型 原型链式继承模式实现了子类对父类的原型的继承,但是,原型链式继承并没有实现代码的复用,且 如果原型中包含引用类型值,那么所有的实例会共享这个属性。

2、构造函数

优点:构造函数模式继承实现了代码的复用;缺点:不能继承借用的构造函数的原型,只能借用构造 函数本身的属性和方法;每次构造函数都要多走一个函数

3、组合继承

组合继承,既能达到对父类属性的继承,也能继承父类原型上的方法;父类属性继承也不会在所有子 类的实列上共享;唯一缺点,子类原型上有父类构造函数的属性,也就是多了一份属性

4、寄生组合继承

寄生组合式继承是对组合继承的进一步优化如果所有继承该父类的子类对象的原型都指向同一个了 ,显然是错误的;不能直接继承,可以间接继承xxx.prototype ;我们让一个函数去指向 xxx.prototype,然后让xxx.prototype指向这个函数产生的对象 .

ES6中:

1、类的constructor方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有 constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

2、类的继承

在子类的构造函数中,如果显示声明了constructor,则必须要显示的调用super函数,只有调用 super之后,才可以使用this关键字,否则会报错。

:enabled        匹配所有可用元素
:disabled       匹配所有不可用元素
:checked        匹配所有选中的被选中元素(复选框、单选框等,select中的option)
:selected       匹配所有选中的option元素
$.escapeSelector(selector)  className或IDName是有特殊符号

3、类的prototype属性和proto属性

ES5继承方式:

1、原型链继承

2、借用构造函数继承

3、组合继承

4、原型式继承

5、寄生式继承

6、寄生组合继承

7、用 Object.create实现类式继承

三、console的用法

1.分类输出

console.log() 输出普通信息 console.info() 输出提示信息 console.warn() 输出警告信息 console.error() 输出错误信息 注意:console.exception()是console.error()的别名,它们功能相同 console.debug 输出调试信息

2.分组输出

console.group()和console.groupEnd() 包裹分组内容 console.group:开始一组输出信息 console.groupEnd:结束一组输出信息 console.group可嵌套使用 console.groupCollapsed() 生成折叠的分组

3.表格输出

console.table() 可以将传入的对象,或数组以表格形式输出,适合排列整齐的元素

4.查看对象

console.dir() 将DOM节点以树形结构形式进行输出,便于我们查看

5.查看节点

console.dirxml() 显示一个XML表示的node节点

6.条件输出

console.assert(expression,object) 当第一个参数或返回值为真时,不输出内容 当第一个参数或返回值为假时,输出后面的内容并抛出异常

7.计次输出

console.count() 输出内容和被调用的次数 console.countReset() 重置计数器

8.计时功能

console.time() 和Console.timeEnd() 包裹需要计时的代码片段,输出运行这段代码的事件 console.time()中的参数作为计时器的标识,具有唯一性 console.timeEnd()中的参数来结束此标识的计时器,并以毫秒为单位返回运行时间 最多同时运行10000个计时器

9.控制台输出计时器的值

console.timeLog() 该计时器必须已经通过 console.time() 启动

10.返回时间戳

console.timeStamp 事件属性可返回一个时间戳,指示发生事件的日期和时间(从 epoch 开始的毫秒 数)

11.追踪调用堆栈

console.trace 追踪函数被调用的过程

12.性能分析

console.profile() 开始记录性能描述信息 console.profileEnd 停止记录之前已经由Console.profile()开始记录的性能描述信息 console.memory 性能问题很难分析,可能还要考虑是否有内存泄露,可使用此方法来查看当前的 堆的使用情况

13.记录一段时间轴

console.timeLine()和console.timeLineEnd()

14.清空控制台

console.clear() 清除当前控制台的所有输出,将光标回置到第一行

四、数组有哪些常用的操作函数

1、数组元素的添加和删除:

1)、push( )

向数组的最后面插入一个或多个元素,返回结果为新数组的长度

2)、pop( )

删除数组中的最后一个元素,返回结果为被删除的元素

3)、unshift( )

在数组最前面插入一个或多个元素,返回结果为新数组的长度

4)、shift( )

删除数组中的第一个元素,返回结果为被删除的元素

5)、slice( )

从数组中提取指定的一个或多个元素,返回结果为新的数组

6)、splice( )

从数组中删除指定的一个或多个元素,返回结果为被删除元素组成的新数组

7)、fill( )

填充数组:用固定的值填充数组,返回结果为新的数组

2、数组元素的修改和查询:

1)、indexOf(value)

从前往后索引,检索一个数组中是否含有指定的元素

2)、lastIndexOf(value)

从后往前索引,检索一个数组中是否含有指定的元素

3)、includes(item)

数组中是否包含指定的内容

4)、find(function( ) )

找出第一个满足「指定条件返回 true」的元素

5)、findIndex(function( ) )

找出第一个满足「指定条件返回 true」的元素的 index

6)、every( )

确保数组中的每个元素都满足「指定条件返回 true」,则停止遍历,此方法才返回 true

7)、some( )

数组中只要有一个元素满足「指定条件返回 true」,则停止遍历,此方法就返回 true

3、数组的合并和拆分

1)、concat( )

合并数组:连接两个或多个数组,返回结果为新的数组

2)、join( )

将数组转换为字符串,返回结果为转换后的字符串

3)、split( )

将字符串按照指定的分隔符,组装为数组

4、数组排序

1)、reverse( )

反转数组,返回结果为反转后的数组

1)、sort( )

对数组的元素,默认按照Unicode 编码,从小到大进行排序

5、遍历数组

for 循环

1)、forEach( )

和 for 循环类似,但需要兼容 IE8 以上

2)、map( )

对原数组中的每一项进行加工,将组成新的数组

3)、filter( )

过滤数组:返回结果是 true 的项,将组成新的数组,返回结果为新的数组

4)、reduce( )

接收一个函数作为累加器,返回值是回调函数累计处理的结果

6、数组的转换和判断

1)、toString( )

数组转换为字符串

2)、isArray( )

判断是否为数组

3)、Array.from( )

将伪数组转换为真数组

4)、Array.of( )

创建数组

五、JS 设计模式

工厂模式

工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新 创建的对象,用工厂方法代替 new 操作的一种模式。

单例模式

单例模式是一种常用的模式,我们在多次引入其他模块时,并不需要每次都创建一个新的模块对象,复 用之前创建过的对象不仅能减少内存的开销,同时也可以体验共享对象带来的便利。简单来说就是使用 闭包持久保存函数上一次的执行结果,在之后的调用中直接返回。例如 js 中模块加载的方式: require、import 都使用到了该模式

classCreator {
create(name) {
returnnewAnimal(name);
}
}
classAnimal {
constructor(name) {
this.name=name;
}
}
varcreator=newCreator();
varduck=creator.create("Duck");
console.log(duck.name); // Duck
varchicken=creator.create("Chicken");
console.log(chicken.name); // Chicken

//构造者和创建者分离,对new操作进行封装且符合开放封闭原则

functionSinglePattern(name) {
if (SinglePattern.instance) {
returnSinglePattern.instance;
}
this.name=name;
this.say=function () {
console.log(this.name);
};
SinglePattern.instance=this;
}
vara=newSinglePattern("aaaaa");
varb=newSinglePattern("bbbbb");
a.say(); // aaaaa

原型模式

原型模式是一种用于创建对象的模式,不同于用类创建,原型模式使用克隆对象的方式来创建一个新的 对象。JavaScript 本身就是一门基于原型的面向对象语言,它的对象系统就是使用原型模式搭建的。

策略模式

定义一系列算法,把他们一个个封装起来,并且可以相互替换

代理模式

定义:当直接访问一个对象不方便或者不满足需要时,为其提供一个替身对象来控制对这个对象的访问 简介:代理模式是一种非常有意义的模式,在我们日常开发中有许多常用功能都可以通过代理模式实现 的,例如防抖动函数(debounce 常用于控制用户输入后回调函数触发的时机),节流函数(throttle 常用于控制 resize、scroll 等事件的触发频率)

b.say(); // aaaaa
a===b; // true

//因为单例模式下,只能被实例化一次,当第二次new的时候,返回的是第一次生成的实例

varprototype= {
name: "Jack",
getName: function () {
returnthis.name;
},
};
varobj=Object.create(prototype, {
job: {
value: "IT",
},
});
console.log(obj.getName()); // Jack
console.log(obj.job); // IT
console.log(obj.__proto__===prototype); //true
varstrategies= {
S: function (salary) {
returnsalary*4;
},
A: function (salary) {
returnsalary*3;
},
B: function (salary) {
returnsalary*2;
},
};
varcalculateBonus=function (level, salary) {
returnstrategies[level](salary);
};
console.log(calculateBonus("S", 20000)); // 输出:80000
console.log(calculateBonus("A", 10000)); // 输出:30000

迭代器模式

定义:提供一种方法顺序访问一个聚合对象中的各个元素,而要不需要暴露该对象的内部表示 简介:迭代器模式简单来说就是将迭代过程从业务逻辑中抽离,简化开发,其分为内迭代和外迭代。目前 许多语言都已经内置了迭代器的实现,如 ES5 中的 forEach 函数就是一种内迭代的实现。

发布订阅模式

定义:分离事件创建者和执行者,执行方只需订阅感兴趣的事件发生点。减少对象间的耦合关系,新的 订阅者出现时不必修改原有代码逻辑 简介:发布订阅模式又叫观察者模式,它定义了对象间一种一对多的关系,当一个对象的状态发生改变 时,所有依赖于它的对象都将得到通知。 发布订阅模式在我们日常开发中应用十分广泛,如浏览器的 dom 事件通知机制 (document.addEventListener),以及 vue 框架中数据改变时自动刷新 dom 的双向绑定机制都是基于该 模式

Array.prototype.myEach=function (cb) {
for (letindex=0; index<this.length; index++) {
constelement=this[index];
if (cb(element, index) ===false) {
break;
}
}
};
["a", "b", "c"].myEach(console.log); // a b c
varEvent=function () {
varclientList= {}; // 订阅者数组
this.listen=function (key, cb) {
// 订阅方法
clientList[key] =clientList[key] || [];
clientList[key].push(cb);
};
this.remove=function (key, cb) {
// 取消订阅
varfns=clientList[key];
if (!cb) {
clientList[key] = [];
} elseif (fns&&fns.length) {
clientList[key] =fns.filter((fn) =>fn!==cb);
}
};
this.trigger=function () {
// 通知订阅者
varkey=Array.prototype.shift.call(arguments);
varargs=arguments;
varfns=clientList[key];
var_this=this;
if (fns&&fns.length) {
fns.myEach(function (fn) {

命令模式

定义:将一组行为抽象为对像并提供执行、撤销等方法,解决它与调用者的之间的耦合关系 简介:命令模式是对简单优雅的模式之一,其中“命令”指的是一个执行某些特定事情的指令。该模式适 用于需要向某些对象发出请求,但不知道接受者是谁,也不知道要执行哪些操作。例如我们平时去饭店 点菜是我们并不需要知道这道菜是谁做的怎么做的,我们只需要请服务员把需求写在订单上就可以了。

fn.apply(_this, args);
});
}
};
};
varevent=newEvent();
event.listen("phone", functiongetPhone() {
Array.prototype.unshift.call(arguments, "有个挨千刀的半夜打电话来了他是:");
console.log.apply(this, arguments);
});
event.trigger("phone", "大狗子"); // 有个挨千刀的半夜打电话来了他是:大狗子
event.trigger("phone", "二狗子"); // 有个挨千刀的半夜打电话来了他是:二狗子
varclient= {

// 顾客(命令发出者)

name: "铁蛋儿",
};
varcook= {

// 厨师(命令发执行者)

makeFood: function (food) {
console.log("开始做:", food);
},
serveFood: function (client) {
console.log("上菜给:", client.name);
},
};
functionOrderCommand(receiver, food) {
// 命令对象
this.receiver=receiver;
this.food=food;
}
OrderCommand.prototype.execute=function (cook) {

// 提供执行方法

cook.makeFood(this.food);
cook.serveFood(this.receiver);
};
varcommand=newOrderCommand(client, "宫保鸡丁");
command.execute(cook); // 开始做:宫保鸡丁;上菜给铁蛋儿

组合模式

定义:将一系列具有相同方法的对象合并成一个具有该方法的组合对象,统一执行 简介:组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。同时利用对象的多态性,使得 单个对象的使用和组合对象的使用具有一致性。例如我们通过命令模式定义了一系列的命令,并且希望 组合这些命令形成一个命令宏统一的执行。

六、错误类型

1、错误类型有哪些?如何进行更好的调试错误?

主要分为:语法错误,编译错误,逻辑错误 ECMA-262规范了7种错误类型。其中Error是基类,其他6种错误类型是子类,都继承了基类。Error类 型的主要作用是自定义错误对象。 // 定义一些命令

varopenDoorCommand= {
execute: function () {
console.log("开门");
},
};
varopenPcCommand= {
execute: function () {
console.log("开电脑");
},
};
varopenLolCommand= {
execute: function () {
console.log("撸一局");
},
};

// 定义命令宏组合命令

varMarcoCommand= {
list: [],
add: function (command) {
this.list.push(command);
},
execute: function () {
this.list.forEach(function (command) {
command.execute();
});
},
};
MarcoCommand.add(openDoorCommand);
MarcoCommand.add(openPcCommand);
MarcoCommand.add(openLolCommand);
MarcoCommand.execute(); // 开门开电脑撸一局

1)、Error:

普通异常。与thorw语句和try/catch语句一起使用,属性name可以读写异常类型,message属性可以 读写详细的错误信息。

2)、EvalError:

不正确使用eval()方法时抛出

3)、SyntaxError:

出现语法错误时抛出

4)、RangeError:

数字超出合法范围之抛出

5)、ReferenceError:

读取不存在的变量时抛出 1、TypeError: 值的类型发生错误的时候抛出 1、URIError: URI编码和解码错误时抛出

2、错误调试方式有哪些?

1)、console

对象直接把 JavaScript 消息写入控制台,这个对象包含如下方法。

2)、error(message)

在控制台中记录错误消息。

3)、info(message)

在控制台中记录信息性内容。

4)、log(message)

在控制台记录常消息。

5)、warn(message)

在控制台中记录警告消息。

6)、alert()

弹出警告窗口。

7)、debug

开发者调试工具

8)、debugger

断点调试

9)、try…catch

错误处理

10)、throw new Error(message)

抛出错误

七、解决跨域问题

1、同源策略

1)、什么是同源策略?

同源策略 (Same-Origin Policy) 最早由 Netscape 公司提出,是浏览器的一种安全策略。

2)、什么是同源?

同源指的是协议、域名、端口号必须完全相同,任何一个不满足条件都会导致跨域问题。

3)、什么是跨域?

违背同源策略就是跨域。

4)、跨域解决方案有什么?

2、CORS

1)、 CORS是什么?

CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS是官方的跨域解决方案,它的特点是 不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get和post请求。

2)、CORS怎么工作的?

CORS是通过设置一个响应头Access-Control-Allow-Origin来告诉浏览器,该请求允许跨域,浏览器 收到该响应以后就会对响应放行。

3)、相关响应头介绍:

Access-Control-Allow-Origin :允许的域名,该字段是必须的,设置为* ,表示取消跨域限制。

Access-Control-Allow-Credentials :该字段可选。它的值是一个布尔值,表示是否允许发送

Cookie。默认情况下,Cookie不包括在CORS请求之中Access-Control-Expose-Headers :该字段可 选。CORS请求时,XMLHttpRequest 对象的 getResponseHeader()方法只能拿到6个基本字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿 到其他字段,就必须在Access-Control-Expose-Headers里面指定。

4)、不足之处

4.1 需要和后端工程师沟通协商,在服务端取消跨域限制 4.2 任意的请求协议、域名和端口都可以访问后端的接口数据,存在一定的安全风险

3 、JSONP

1)、什么是JSONP ?

JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只 支持get请求。 在网页有一些标签天生具有跨域能力,比如:img link iframe script,JSONP就是利用 script 标签的跨 域能力来发送请求的。

2)、JSONP 使用步骤

3)、不足之处

1它只支持GET请求而不支持POST等其它类型的HTTP请求 2它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。 3 jsonp在调用失败的时候不会返回各种HTTP状态码。 4安全性。万一提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的,所有调用 这个 jsonp的网站都会存在漏洞。

4 代理服务(推荐)

1)、Nginx与Node

在工作上,由于工作平台和语言的原因,对于大部分前端开发人员来说,更倾向于用Nodejs来搭建服务 器,进而实现一些需求,对Nginx有天然的抗拒感。的确,Nginx中的绝大部分功能,如果单纯的使用 Node.js也可以满足和实现。但实际上,Nginx和Node.js并不冲突,都有自己擅长的领域:Nginx更擅长 于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),Node.js更擅长于上层具体 业务逻辑的处理。两者可以实现完美组合,助力前端开发。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: content-type,cache-control
// 1.动态的创建一个script标签
varscript=document.createElement("script");
// 2.设置script的 src
script.src="http://localhost:3000/testAJAX?callback=abc";
// 3. 定义回调函数
functionabc(data) {
alert(data.name);
};
// 4.将script添加到 body 中,会发送请求
document.body.appendChild(script);

2)、反向代理

正向代理:

翻墙工具其实就是一个正向代理工具。它会把们访问墙外服务器server的网页请求,代理到一个可 以访问该网站的代理服务器proxy,这个代理服务器proxy把墙外服务器server上的网页内容获取, 再转发给客户。

反向代理:

客户端发送的请求,想要访问server服务器上的内容。但将被发送到一个代理服务器proxy,这个 代理服务器将把请求代理到和自己属于同一个LAN下的内部服务器上,而用户真正想获得的内容就 储存在这些内部服务器上。 这里proxy服务器代理的并不是客户,而是服务器,即向外部客户端提供了一个统一的代理入口, 客户端的请求,都先经过这个proxy服务器,至于在内网真正访问哪台服务器内容,由这个proxy去 控制。

为什么要Nginx反向代理

使用反向代理最主要的两个原因: (1)安全及权限。 可以看出,使用反向代理后,用户端将无法直接通过请求访问真正的内容服务器,而必须首先通过 Nginx。可以通过在Nginx层上将危险或者没有权限的请求内容过滤掉,从而保证了服务器的安 全。 (2)负载均衡。 单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中 到单个服务器上的情况改为请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所 说的负载均衡。

3)、前后端分离项目

(1)vue项目中的配置

在vue.config.js 文件中,我们需要配置:(vue-cli 3.0)
在config/index.js 文件中,我们需要配置:(vue-cli 2.0)

配置多个代理地址: 情形:某个项目时,由于是多个后端配合(A写一般任务的接口,B写技术预研的接口),出现了多个端 口。因此,前端也需要配置多个代理。

devServer: {
//代理列表
proxy: {
'/api': {
target: 'http://172.31.46.4:8088', //要代理的域名
changeOrigin: true,//允许跨域
pathRewrite: {
'^/api': ''  // 这个是定义要访问的路径,名字随便写
}
}
}
}
dev: {
proxyTable: {
'/api': {
target: 'http://172.31.46.4:8088', //要代理的域名
changeOrigin: true,//允许跨域
pathRewrite: {
'^/api': ''  // 这个是定义要访问的路径,名字随便写
}
}
}
}
/api/getUserMsg` 相当于 `http://172.31.46.4:8088/getUserMsg
/api`相当于`http://172.31.46.4:8088
this.$http.get("/api/getUserMsg", {
}
.then(res=> {
})
.catch(function(error) {
});
devServer: {
//代理列表
proxy: {
'/mps-ss': {
target:'http://xxxxxx:7890',//线上1
changeOrigin: true,
pathRewrite: {
'^/mps-ss': '/mps-ss'
}

这个时候,我们可能会疑惑,为什么有的pathRewrite 这个对象,内容不同。 这因为,后端接口匹配的路由不同。 例如:(以nodejs 模拟的接口),针对情况一

},
'/mps-fileApi': {
target:'http://xxxxx:7777',//线上2
changeOrigin: true,
pathRewrite: {
'^/mps-fileApi': '/mps-fileApi'
}
},
'/mps-video': {
target:'http://xxxxxx:8090',//返回播放地址
changeOrigin: true,
pathRewrite: {
'^/mps-video': '/mps-video'
}
}
}
}

// 情况一:

'/api': {
target:'http://172.31.242.10:7890',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
}
}
//上下两个pathRewrite对比,会发现,匹配^/mps-ss会等于 '/mps-ss',另一个是匹配^/mps-ss会
等于 '/'

// 情况二:

'/api': {
target:'http://172.31.242.10:7890',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}

(以nodejs 模拟的接口),针对情况二

(2)react配置跨域(两种)

(1)(在package.json 里配置proxy),单一代理 1,如代理到本地服务器5000端口, “proxy”:“http://localhost:5000”

2,本地服务器是由nodejs 启动的(express)。路由:app.get('/getStudentsMsg',

(req,res)=>{}) 。所以,在axios 做请求数据时,直接请求:‘http://localhost:3000/getStuden tsMsg’。(详情查看app.js 文件中的button点击事件) (2)(不在package.json 里配置proxy,而在项目目录src/ 下新建setupProxy.js 文件),多个 代理 如果在package.json 文件中配置:(报错:提示只支持string类型,不支持object.)

app.get('/cars',(req,res)=>{
letdata= [
{name:'宝马',price:'32万',sell:1230192},
{name:'奥迪',price:'23.4万',sell:21091},
{name:'奔驰',price:'46万',sell:721912}
]
res.send(data)
})

解决方法:

安装http-proxy-middleware 管理包,cnpm http-proxy-middleware --save (注意,在

create-react-app 脚手架已经下载好了依赖。此步骤可以省略) 在项目目录src/ 下新建setupProxy.js 文件,然后写入如下代码:

八、react

1、什么是React

1)、与2011年由facebook开发,2013年开源,被bat等公司广泛运用 2)原生js很难操作UI界面,React遵循组件设计模式,声明式编程和函数式编程,使用虚拟DOM来操作 DOM,单向响应数据流,组件复用,客户端渲染也支持服务端渲染,还支持移动端app开发,扩展性 强,良好的生态 3)、是一个为数据提供渲染为html试图的javascript库 4)、特点和高效原因

"proxy":{
"/api": {
"target": "http://172.19.5.35:9536",
"ws": true
},
"/apc": {
"target": "http://179.19.5.35:9536",
"ws": true
}
},

//做多个代理的配置文件

constproxy=require('http-proxy-middleware');
module.exports=function (app) {
app.use(
proxy(
'/api', {  //遇见 /api前缀的请求,就会触发该代理配置
target: 'http://localhost:5000',
changeOrigin: true,  // 控制服务器接收到的请求头host的值
pathRewrite: {
"^/api": "/api"
}
}),
proxy(
'/apc', {
target: 'http://localhost:7000',
changeOrigin: true,
pathRewrite: {
"^/apc": ""
},
}
)
)
};

(1)、声明式编程 (2)、组件化编程 (3)、可使用react native编写原生应用 (4)、优秀的diff算法 (5)、使用虚拟(virtual)DOM,不总是直接操作页面真实 DOM (6)、DOM Diffing 算法,最小化页面重绘

2、开发准备

1)、React 运行环境的依赖资源

(1)、react.development.js(React 的核心库,当前版本为开发版本) (2)、react-dom.development.js(React 的扩展库,当前版本主要操作 DOM 渲染,因为现在开发环 境是在 PC 网页端) (3)、babel.min.js(ES6 转 ES5,JSX 转 JS) (4)、prop-types.js(属性类型的检测与约束库)

2)、Babel

(1)、Babel 是一个 JavaScript 编译器

3)、能干什么:

(1)、语法转换 (2)、源码转换 (3)、通过 Polyfill 方式在目标环境中添加缺失的特性

4)、Babel与JSX 以及 React的关系

(1)、Babel 能够转换 JSX 语法,之前引入babel.min.js的目的就是将JSX转成ES语法

3、DOM

1)、虚拟DOM创建

2)、虚拟 DOM 与真实 DOM

(1)、虚拟DOM本质是一个Object对象,非常“轻” (2)、真实DOM的属性节点非常多非常“重” (3)、最终是需要将虚拟DOM转成真实DOM

(1)、1.   <script type="text/babel">    const VDOM = <h1 id="title"> Hello
React</h1>
(2)、2.<script type="text/javascript">    const VDOM =React.createElement("h1",
{ id: "title" },"Hello React"))

4、JSX 语法规则

1)、虚拟DOM定义的时候不能使用字符串型式,不要写引号 2)、标签结构中需要混入js表达式,要用{}做分割,即:{js表达式} 3)、指定样式的类名不要用class,建议使用className 4)、行内样式,要用style={{}}的形式去编写,且像font-size这样的样式需要改写成驼峰式写法,不是 必须,会出警告 5)、JSX有且只有一个根元素 6)、标签必须闭合 7)、标签首字母 (1)假若标签首字母是小写,即将该标签转为html的同名元素,若html中无该元素,那么则警告 ( 2)若标签首字母是大写,那么则会被认为是React组件,而这时候将会去找这个组件,如果没有定义 过这个组件,将直接报错

5、组件与模块

1)、模块

(1)、什么是模块:向外提供特定功能的js程序,一般就是一个js文件 (2)、为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂 (3)、作用:复用js,简化js的编写,提高js运行效率 (4)、什么是模块化开发:模块定义、接口暴露、模块引入、模块调用 (5)、模块化开发规范有哪些?AMD(异步模块定义,代表:requireJs)、CMD(通用模块定义,代 表:seaJs)、CommonJs(nodejs服务器端模块化规范)、ES6

2)、组件

(1)、什么是组件:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等) (2)、为什么要用组件:随着业务功能的增加,相同、相似的功能操作内容重复使用率大幅度提升, 简单的复制粘贴会使得项目代码可维护性降低 (3)、作用:复用编码,简化项目编码,提高运行效率 (4)、什么是组件化开发:组件定义(HTML、CSS、JS、Images、Fonts、Files…)、组件暴露、组件 引入、组件调用

6、React组件

1)、类组件

2)、函数式组件

(1)、使用函数定义一个组件 (1.1)、注意:在函数式组件中,this对象是undefined,其原因是React+Babel默认返回是strict严 格模式 (1.2)、注意:.一般情况在进行渲染的时候不用函数调用模式,而是使用组件调用模式 (1.3)、注意:如果是函数式组件,进行组件化调用,则必须是首字母大写 (2)、渲染组件到页面 (2.1)、注意:是否能写成Hello、Hello()、,不能 (2.2)、注意:在JSX中,Hello是组件,而不是普通函数,所以不是函数调用操作 (2.3)、执行了ReactDOM.render(…后发生了什么??? (2.3.1)、React发现了标签,寻找Hello组件定义的位置 (2.3.2)、React发现Hello组件使用函数定义的,React去调用Hello

九、什么是CDN

1.什么是CDN?

CDN的全称是Content Delivery Network,即内容分发网络。 CDN是一个空间换时间的策略。 CDN使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。 CDN依靠部署在各地的边缘服务器,包括中心平台的负载均衡、内容分发、调度等功能模块。

2.什么时候使用CDN?

解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。使用户可 就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度和成功率。 控制时延无疑是现代信息科技的重要指标,CDN的意图就是尽可能的减少资源在转发、传输、链路抖动 等情况下顺利保障信息的连贯性。

3.为什么需要使用CDN?

1)为了加速网站的访问; 2)为了实现跨运营商、跨地域的全网覆盖 互联不互通、区域ISP地域局限、出口带宽受限制等种种因素都造成了网站的区域性无法访问。CDN加速 可以覆盖全球的线路,通过和运营商合作,部署IDC资源,在全国骨干节点商,合理部署CDN边缘分发 存储节点,充分利用带宽资源,平衡源站流量。 3)为了保障你的网站安全 CDN的负载均衡和分布式存储技术,可以加强网站的可靠性,相当无无形中给你的网站添加了一把保护 伞,应对绝大部分的互联网攻击事件。防攻击系统也能避免网站遭到恶意攻击。 4)为了异地备援 当某个服务器发生意外故障时,系统将会调用其他临近的健康服务器节点进行服务,进而提供接近100% 的可靠性,这就让你的网站可以做到永不宕机。 5)为了节约成本投入 使用CDN加速可以实现网站的全国铺设,你根据不用考虑购买服务器与后续的托管运维,服务器之间镜 像同步,也不用为了管理维护技术人员而烦恼,节省了人力、精力和财力。 6)为了让你更专注业务本身 CDN加速厂商一般都会提供一站式服务,业务不仅限于CDN,还有配套的云存储、大数据服务、视频云 服务等,而且一般会提供7x24运维监控支持,保证网络随时畅通,你可以放心使用。并且将更多的精力 投入到发展自身的核心业务之上。

4.它的优势与不足是什么?

优势:

1)更快地传递内容 由于CDN最靠近用户放置,因此当内容需要移动的距离更短时,可以减少延迟。CDN可以使网站加载速 度更快。例如,如果网站位于英国并且从美国获得流量,则CDN提供商可能在美国拥有服务器并将该服 务器用于网站。 2)更多同步用户 CDN可以确保网络具有高数据阈值。因此,大量用户可以在没有延迟的情况下同时访问网络。通过实现 高流量,CDN允许来自世界各地的人们同时访问网站。 3)持续可用性 CDN中的服务器始终在运行,即使服务器已关闭,网站也可以访问。如果没有CDN,服务器有时可能会 关闭,这意味着必须等到主机解决问题。如果使用CDN,则不会发生这种情况。如果服务器崩溃,CDN 将使用缓存页面。 4)可靠的内容传递 如果使用CDN,则内容的传送更加一致。特别是,这涉及高分辨率内容,如视频和图像。CDN提供高质 量的内容交付,因此对网站的性能产生重大影响。由于54%的客户希望在的网站上看到视频,因此可以 以高分辨率提供这些视频对业务至关重要。 5)控制资产交付 当CDN监控资产交付时,运营商可以根据实时统计数据确定需要额外容量的位置。如果某个地区的服务 器出现过载,运营商可以提供额外的带宽,以确保一切顺利运行。 6、防止流量高峰 如果网站突然出现大量流量,可以从CDN服务中受益。大型服务器网络可确保这些资源在所有情况下都 可用且可扩展。许多企业的噩梦是他们将获得大幅增加的流量,但他们的网站无法处理它。 不足: 1)成本 这可能是使用CDN的最重要的缺点。开始使用CDN服务的成本很高,而且它们也有许多隐藏成本。其中 包括每次数据传输和千兆字节的成本。高成本来自第三方网络。启动新的CDN网络要求服务器公司从另 一家公司获得帮助以安装此类网络。请务必仔细阅读所有条款和条件。 鉴于此,CDN网络往往是能够负担这些成本的大公司的更好选择。在全球范围内维护无用的复制服务器 也是不切实际的。 2)服务地点 如果大多数受众群体位于CDN没有服务器的国家/地区,则网站上的数据可能需要比不使用任何CDN更进 一步。 3)限制 一些组织和国家已阻止流行CDN的域或IP地址。在这种情况下,来自这些组织或国家/地区的受众群体无 法访问网站,最终会失去部分流量。 4)支持可用性 当第三方供应商负责运行CDN时,会出现支持问题。如果出现技术问题,即使很少见,无法知道操作员 需要多长时间来解决问题并防止再次发生问题。 5)失去控制 是否愿意将网站文件移交给另一家公司?在决定是否使用CDN之前,必须考虑这一点。使用CDN意味着 第三方会收到有关网站和系统的信息。

十、深拷贝与桥拷贝

1.什么是深拷贝与浅拷贝

浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型, 拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改 变了这个地址,就会影响到另一个对象。 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修 改新对象不会影响原对象。

2.深拷贝与桥拷贝的区别

浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类 型因共享同一块内存,会相互影响。 深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两 个对象互不影响。 浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。

3.深拷贝与浅拷贝的实现方式

1.浅拷贝的实现方式

1.Array.concat( )

2.Array.slice( )

3.Object.assign( )

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对 象。 语法:Object.assign(target, source1, source2) target:目标对象 source:源对象

letarr= ['a', 'b', 'c'];
letnewArr=arr.concat();
newArr.push('d');
console.log(arr);    // ["a", "b", "c"]
console.log(newArr); // ["a", "b", "c", "d"]
letarr= ['a', 'b', 'c'];
letnewArr=arr.slice();
newArr.push('d');
console.log(arr);    // ["a", "b", "c"]
console.log(newArr); // ["a", "b", "c", "d"]

4.展开运算符

2.深拷贝的实现方式

1.JSON.parse(JSON.stringify())

2.jQuery.extend( )

语法:$.extend( [deep ], target, object1 [, objectN ] ) deep:Boolean类型,指示是否深度合并对象,默认为false。如果该值为true,且多个对象的某个 同名属性也都是对象,则该”属性对象”的属性也将进行合并。

letobj1= { person: {name: "张三", age: 18},sex:'男' };
letobj2=Object.assign({}, obj1);
obj2.person.name="李四";
obj2.sex='女'
console.log(obj1); // { person: { name: '李四', age: 18 }, sex: '女' }
letobj1= {
name: '张三',
address: {
x: 100,
y: 100
}
}
letobj2= {
...obj1
}
obj1.address.x=200;
obj1.name='wade'
console.log (obj2); // { name: '张三', address: { x: 200, y: 100 } }
letarr= [1, 2, {
name: ' 张三'
}];
letnewArr=JSON.parse(JSON.stringify(arr));
newArr[2].name='李四';
console.log(arr);//[1, 2, {name = '张三'}]
console.log(newArr);//[1, 2, {name = '李四'}]
letobj1= {
a: 1,
b: {
f: {
g: 4
}
},
c: [1, 2, 3]
};
constobj2=$.extend(true, {}, obj1);
console.log(obj1.b.g===obj2.b.f.g); // false

4.深拷贝与浅拷贝的应用场景

无论是浅拷贝还是深拷贝,一般都用于操作Object 或 Array之类的复合类型。 对于一层结构的Array和Object想要拷贝一个副本时使用,使用浅拷贝 对于想对某个数组或对象的值进行修改,但是又要保留原来数组或对象的值不被修改,此时就可以 用深拷贝来创建一个新的数组或对象,从而达到操作(修改)新的数组或对象时,保留原来数组或对 象。

十一、event.target与event.currentTarget的差异

1.什么是target?什么是currentTarget?

event.target 是发生事件的元素或触发事件的元素。 event.currentTarget 是我们在其上显式附加事件处理程序的元素。(是事件绑定的元素)

2.target和currentTarget的区别:

  1. target:触发事件的元素。
  2. currentTarget:事件绑定的元素。
  3. 两者在没有冒泡的情况下,是一样的值,但在用了事件委托的情况下event.target指向引起触发事 件的元素,而event.currentTarget则是事件绑定的元素。
  4. 小结:currentTarget始终是监听事件者,绑定谁就是谁,而target是事件的真正发出者,点谁就是 谁。

一、针对部分监听事件,例如onclick:

1、如果你点击的是添加事件元素的子元素,就用currentTarget来获取父元素的值,用target来获取 子元素的值; 2、如果没有子元素,就在本元素上添加事件,target和currentTarget效果一样。

二、针对部分监听事件,例如onmouseenter:

1、如果你点击的是添加事件元素的子元素。使用currentTarget或者target都是获取父元素的值; 2、如果没有子元素,就在本元素上添加事件,target和currentTarget效果都是获取到自身元素的 值。

三、针对部分监听事件(比如onclick):

  1. target指向的是事件触发事的元素。 target在事件流的目标阶段,没有事件流的捕获和冒泡。点击始终是指向被单击的对象
  2. currentTarget指向事件绑定的元素。 当事件流处在目标阶段的时候(就是点击当前事件绑定对象),指向被单击的对象 当处于捕获和冒泡阶段的时候,指向当前事件活动的对象(一般为父级)。

3. 什么时候使用target和currentTarget?

1.target在事件流的目标阶段

当事件流处在目标阶段的时候(就是点击当前事件绑定对象),指向被单击的对象 当需要获取不同子组件绑定的属性,比如点击某个组件拿到该组件上绑定的属性,可以使用 event.target

2 . currentTarget在事件流的捕获,目标及冒泡阶段。

当事件流处在目标阶段的时候(就是点击当前事件绑定对象),指向被单击的对象 当处于捕获和冒泡阶段的时候,也是指向当前事件绑定的对象。 始终都可以找到当前绑定事件的对象,所以开发人员一般使用event.currentTarget属性,event.target 属性很少使用 一般情况下,建议只使用 currentTarget 对象,因为它能拿到我们想要的参数属性 如果我们需要获取不同子组件绑定的属性,比如点击某个组件拿到该组件上绑定的属性,才用 target 对 象

4.current的不足:

通过查询MDN了解到,currentTarget在Safari on iOS10.0以下的版本中兼容性较差。

十二、动画库

一、CSS的常用动画库

1、Animista

网站地址:http://animista.net/ 网站描述:在线生成css动画 Animista是一个在线动画生成器,同时也是一个动画库,它为我们提供了以下功能

2、Animate CSS

网站地址:http://daneden.github.io/anim… 网站描述:齐全的CSS3动画库 想必这个不用介绍,大部分人都知道了。Animate CSS可能是最著名的动画库之一。

3、Vivify

网站地址:http://vivify.mkcreative.cz/ 网站描述:一个更加丰富css动画库 Vivify是一个动画库,可以看作是Animate CSS的增强版。它们的工作方式完全相同,有Animate CSS 的大多数类且还扩展了一些。

4、Magic Animations CSS3

网站地址:https://www.minimamente.com/p… 网站描述: Magic CSS3 Animations 是 CSS3 动画的包,伴有特殊的效果,用户可以自由的在 web 项目 中使用。 这个动画库有一些非常漂亮和流畅的动画,特别是3D的。没什么好说的,自己去尝试。

5、Angrytools

网站地址:https://angrytools.com/css/an… 如果使用不同的生成器,Angrytools实际上是一个集合,其中还包括CSS动画生成器。

6、Hover.css

网站地址:http://ianlunn.github.io/Hover/ 网站描述:纯CSS3鼠标滑过效果动画库 Hover.css是许多CSS动画的集合,与上面的动画不同,每次将元素悬停时都会触发。

7、WickedCSS

网站地址:http://kristofferandreasen.gi… WickedCSS是一个小的CSS动画库,它没有太多的动画变体,但至少有很大的变化。其中大多数是我们 已经熟悉的基础知识,但它们确实很干净。

8、Three Dots

网站地址:https://nzbin.github.io/three Three Dots是一组CSS加载动画,它由三个点组成,而这些点仅由单个元素组成。

9、CSShake

网站地址:https://elrumordelaluz.github 顾名思义,CSShake是一个CSS动画库,其中包含不同类型的震动动画。

二、JS的常用动画库

1.Three.js

2. Anime.js

3.Mo.js

4. Velocity

5. Popmotion

6. Vivus

7. GreenSock JS

8. Scroll Reveal

9. Typed.js

十三、动画类型(CSS3和JS)

一、css3动画

1.过渡动画(transition)

1.1概念

允许 CSS 的属性值在一定时间区间内平滑的过渡,在鼠标点击,鼠标滑过或对元素任何改变中触发,并 圆滑地以动画改变css的属性值 1.2CSS3 过渡语法 transition-delay :检索或设置对象延迟过渡的时间 transition-duration :检索或设置对象过渡的持续时间 transition-property :检索或设置对象中的参与过渡的属性 all | none | property,property … all:所有可以进行过渡的css属性 none:不指定过渡的css属性 property:指定要进行过渡的css属性 transition-timing-function:检索或设置对象中过渡的动画类型 transition-timing-function:linear | ease | ease-in | ease-out | ease-in-out | cubic- bezier(number, number, number, number) 检索或设置对象中过渡的动画类型 如果提供多个属性值,以逗号进行分隔 http://cubic-bezier.com/(贝塞尔曲线生成器)

1.3注意事项

并不是所有元素都支持过渡 元素没有渲染完的情况下,过渡不生效 2.关键帧动画(animation)

2.1概念

通过 CSS 提供的@keyframes规则整合多个简单的动画,它会指定某个动画的名称以及相应的规则: 哪个属性,何时以及何地渲染动画。然后使用animation属性把动画绑定到相应的元素上,并为其添 加额外的参数

2.2关键帧

CSS3 动画语法-关键帧: keyframes 控制关键位置,并不是所有的位置 keyframes-selector:必写项,动画持续时间的百分比 0% - 100%之间,或者使用from和to关键字也可以设置,from代表0%,to代表100%

2.3关键帧的使用

基础语法: animation-name:move; 动画属性名,前面keyframes样例定义的动画名 animation-duration: 10s; 动画持续时间 animation-timing-function: ease-in-out; 检测的是关键帧的区间,并不是整个动画过程 animation-delay: 2s; 动画延迟时间 animation-iteration-count: 10; 动画循环次数,infinite为无限次 animation-direction: normal; 定义动画播放方式 动画的暂停和播放 animation-play-state 属性 paused:规定动画已暂停 running:规定动画正在播放 动画开始和结束状态 animation-fill-mode 属性 none:使用得动画不会对动画等待和动画完成的元素样式产生改变 forwards:告诉浏览器动画结束后,元素的样式将设置为动画的最后一帧的样式 backwards :那么在动画等待的那段时间内,元素的样式将设置为动画第一帧的样式 both:在动画等待和动画结束状态,元素将分别应用动画第一帧和最后一帧的样式

二、js动画

1.使用 setInterval

通过一个定时器setInterval间隔来改变元素样式,动画结束时clearInterval即可 2.使用 requestAnimationFrame requestAnimationFrame是另一种Web API,原理与setTimeout和setInterval类似,都是通过 javascript持续循环的方法调用来触发动画动作。 但它与setTimeOut()不同的是,它是根据浏览器的刷新同步进行动画。而定时器是按照自己的思路走 的

3.Jquery的animate函数

@keyframesname{
[keyframes-selector] { Properties:Propertiesvalue; }
[keyframes-selector] { Properties:Propertiesvalue; }
}

三、html5动画

canvas svg webgl

四.对比css动画和js动画

1.使用场景选择

使用 CSS 动画来实现较简单的“一次性”转换,例如切换 UI 元素状态。 需要高级效果(例如弹跳、停止、暂停、倒退或减速)时,使用 JavaScript 动画 如果选择使用 JavaScript 来编写动画,可选用 Web Animations API 或用起来顺手的现代框架

2.css动画性能

优点 不足: 1、不能动态的修改或定义动画内容 2、不同的动画无法实现同步 3、多个动画彼此无法堆叠

3.js动画性能

优点:

  1. js动画控制能力强,可以在动画博凡过程中对动画进行精细控制,开始、暂停、终止、取消都是可 以做到的
  2. 动画效果比css3动画丰富,比如曲线运动,冲击闪烁,视差滚动效果,只有js动画才能完成
  3. js动画大多数情况下没有兼容性问题,而css3动画有兼容性问题 不足:
  4. js动画的复杂度高于css3
  5. js在动画浏览器的主线程中执行,而主线程还有其他javaScript脚本,样式计算、布局、绘制任务 等,对其干扰可能出现阻塞从而出现丢帧的情况
  6. js动画往往需要频繁操作DOM的css属性来实现视觉上的动画效果,这个时候浏览器要不停地执行 重绘和重排,这对于性能的消耗是很大的,尤其是在分配给浏览器的内存没那么宽裕的移动端。

4.CSS动画比JS流畅的前提

在Chromium基础上的浏览器中 JS在执行一些昂贵的任务 同时CSS动画不触发layout或paint 在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动 画或JS动画都会阻塞后续操作。 1、css3动画相比JS更轻量,性能更好,更易于实现 2、不必担心缺乏标准和增加带宽消耗的问题 3、不依赖于主线程,采用硬件加速(GPU) 4、move.js是一个封装了css3动画效果的轻量级js动画库

十四、如何实现数据类型的转换

JavaScript是一门动态语言,所谓的动态语言可以暂时理解为在语言中的一切内容都是不确定的。比如一 个变量,这一时刻是个整型,下一时刻可能会变成字符串了。虽然变量的数据类型是不确定的,但是各 种运算符对数据类型是有要求的。如果运算符发现,运算子的类型与预期不符,就会自动转换类型。 自动转换是基于强制转换之上。强制转换主要指使用Number、String和Boolean三个函数,手动将各种 类型的值,分布转换成数字、字符串或者布尔值

一.强制转换

1.类型转换之String()

String方法是可以将其他类型转换成字符串类型 1.null类型的转换 String(null) 字符串的 ‘null’ 2.undefined转换 String(undefined) 字符串的’undefined 3.number类型的转换 转换规则:普通数字直接变成字符串其他进制先转换成10进制然后在转换成相应的字符串无穷大无穷 小NaN都直接变成字符串 String(123) ‘123’ String(-123) ‘-123’ String(010) ‘8’ String(0xff) ‘255’ String(4E-5) ‘0.00004’ String(Infinity) ‘Infinity’ String(-Infinity) ‘-Infinity’ String(12.3) ‘12.3’ String(NaN) ‘NaN’ 4.布尔值的转换 String(true) ‘true’ String(false) ‘false’ 5.对象的转换 String([]) 空字符串 ” String([1]) ‘1’ String([1,2,3]) ‘1,2,3’ String({}) [object object] String({name:“lily”}) [object object]

2.类型转换之toString()

我们的代码中有+(加号)运算符等情况下,它在这种情况下(字符串 + 其它什么东西),会调用 toString()方法,将其它类型的东西转化为字符串,再和原始字符串拼接成一个字符串 除了null和undefined之外,其他的类型(数值、布尔、字符串、对象)都有toString()方法,它返回 相应值的字符串表现(并不修改原变量)。 每个对象都有一个toString()方法。 当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。 (1).toString() “1” [1,2].toString() “1, 2” ({}).toString() [object Object] true.toString() “true” null.toString() Uncaught TypeError: Cannot read property ‘toString’ of null undefined.toString() Uncaught TypeError: Cannot read property ‘toString’ of null

3.类型转换之Number()

Number()方法将其他类型转换成number类型 Number方法会返回一个转换后的值 1.Number() 数字转数字还是原来的值 2.字符串转数字 Number("") 空字符串—>0 (Number(” ”) 都是空格的字符串—>0 (Number(“123”) 纯数字的字符串—>相对应的数字 Number(“1a23”) 非纯数字的字符串—>NaN 3.布尔值转数字 Number(true) true—>1 Number(false) false—>0 4.undefined转数字 Number(undefined) undefined—>NaN 5.null转数字 Number(null) null--->0 6.object(数组和对象)转数字 Number([]) 空数组—>0 Number([1,2,3]) 一般非空数组—>NaN Number([1]) 数字只有一个值,并且是数字—>当前数字 Number([“1”]) 数字只有一个值,并且是数字值的字符串—>当前数字 Number([“a”]) 数字只有一个值,并且是非数字—>NaN Number({}) 空对象—>NaN Number({name:“lily”}) 非空对象—>NaNz

4.类型转换之Boolean()

布尔类型仅包含两个固定的值:true 和false 。其中true 代表真,false 代表假 1.null Boolean(null) false 2.undefined Boolean(undefined) false 3.number 数字转布尔值非0为true 0为false NaN为false Boolean(123) true Boolean(-123) true Boolean(0) false Boolean(1.23) true Boolean(NaN) false Boolean(Infinity) true Boolean(010) true Boolean(0xa) true 4.string 空为false 非空为true Boolean(“123”) true Boolean("") false Boolean(” ”) true 5.object 对象类型都转换成true Boolean([]) true Boolean([1,2,3]) true Boolean([0]) true Boolean({}) true Boolean({name:“lily”}) true

5.类型转换之parseInt()

parseInt是一个全局方法,它可以把值转换为整数 第1步,先解析位置0处的字符,如果不是有效数字,则直接返回 NaN。 第2步,如果位置0处的字符是数字,或者可以转换为有效数字,则继续解析位置1处的字符,如果不是有 效数字,则直接返回位置0处的有效数字。 第3步,以此类推,按从左到右的顺序,逐个分析每个字符,直到发现非数字字符为止。 第4步,parseInt()将把前面分析合法的数字字符全部转换为数值并返回。 注意:浮点数中的点号对于parseInt来说属于非法字符,因此不会转换小数部分值。如果是以0开 头的数字字符串,则parseInt()不会把它作为八进制数字处理如果是以0x 开头的数字字符串,则 parseInt()会把它作为十六进制数字处理:先把它转换为十六进制数值,然后再转换为十进制的数字 返回。 parseInt(123) 123 parseInt(“a123”) NaN parseInt(“1a123”) 1 parseInt(“10a23”) 10 parseInt(“100px”) 100 parseInt(12.3) 12 parseInt(“0xa”) 12 parseInt(null) NaN parseInt(true) NaN parseInt 支持基模式,把不同进制的数字字符串转换为整数 let a = “abc123”; parseInt(a,16) 11256099 把a当成16进制,转化为10进制输出 let b = “111”; parseInt(b,2) 7 parseInt(5,3) NaN 因为3进制没有5这个字符 特殊情况如下: parseInt(1,1) NaN parseInt(0,1) NaN parseInt(0,0) 0

6.类型转换之parseFloat()

parseFloat()也是一个全局方法,它可以把值转换成浮点数,即它能够识别第一个出现的小数点, 而第二个小数点视为非法。解析过程和parseInt相同。 parseFloat()的参数必须是十进制的字符串,对十六进制和八进制前的0进行忽略或返回0。 parseFloat(123) 123 parseFloat(12.3) 12.3 parseFloat(“12.3.3”) 12.3 parseFloat(“a12.1”) NaN

二.自动转换

1.类型转换之算数运算符

如果说变量进行运算就会被自动隐式转换为数字类型,如果无法转换成合法数值就变成NaN 1.一元运算+ let y = ‘5’; let x = +y; x为number类型的5 let y = ‘piggy’; let x = +y; x为NaN 2.乘法 let a = “1”; console.log(a * 1) number类型的 1 let b = “1a”; console.log(b * 1) NaN 3.加法(字符串的加法运算不在此列) let c = 1; console.log(c + true) number类型的 2 let d = 1; console.log(d + NaN) NaN(任何值和NaN做运算都得NaN) 4.除法 let e = “1”; console.log(e / 1) number类型的 1 let f = “1a”; console.log(f / 1) NaN 5.减法 let g = “1” console.log(g - 0) number类型的 1 let h = “1a”; console.log(h - 0) NaN

2.类型转换之双重逻辑非

JavaScript 遇到预期为布尔值的地方(比如if语句的条件部分),就会将非布尔值的参数自动转换为布尔值。 系统内部会自动调用Boolean函数。 一个逻辑非运算符(!)可以把值转换为布尔值并取反,两个就是转换成正确的布尔值 console.log(!!0) false console.log(!!1) true

十五、冒泡事件

1.事件冒泡以及相关

1.1.事件冒泡event bubble

当一个元素接收到事件的时候会把他接收到的事件传给自己的父级,一直到window 。 注意这里传递的仅仅是事件并不传递所绑定的事件函数。所以如果父级没有绑定事件函数,就算传递了 事件也不会有什么表现但事件确实传递了。

1.2.事件捕获event capturing

当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如 果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。

2.事件委托以及相关

2.1.事件委托Event Delegation

事件委托也称之为事件代理,事件委派。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代 理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。事件代理的 原理是DOM元素的事件冒泡。

2.1.1.事件委托的优点

1)减少事件注册,节省内存,例如: 在table上代理所有td的click事件。 在ul上代理所有li的click事件。 2)简化了dom节点更新时,相应事件的更新。比如: 不用在新添加的li上绑定click事件。 当删除某个li时,不用移解绑上面的click事件。

2.1.2.事件委托的不足

1)事件委托基于冒泡,对于不冒泡的事件不支持。 2)层级过多,冒泡过程中,可能会被某层阻止掉。 3)理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在 table上代理td,而不是在document上代理td。

if ('abc') {  console.log('hello')
}  // "hello"

4)把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件, 另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。

3.阻止事件冒泡与默认事件的方法

3.1.event.stopPropagation()方法

这是阻止事件的冒泡方法,不让事件向documen上蔓延,但是默认事件任然会执行,当你调用这个方法 的时候,如果点击一个连接,这个连接仍然会被打开。

3.2.event.preventDefault()方法

这是阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的 父元素。

3.3.return false方法

这个方法比较暴力,他会同事阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也 不会传递到上一层的父元素;可以理解为return false就等于同时调用了event.stopPropagation()和 event.preventDefault().

十六、选择有哪些

1、共有的选择器

选择器(JQ & CSS)

说明

#id ID选择器 .class 类选择器 element element 后代选择器,用于选择元素内部的元素 element,element 多选择器组合 element+element 兄弟选择器,用于选择(不是内部)指定的第一个元素之后紧跟的元素 element>element 子代选择器,选择直接子元素而不包括子元素的后代 element1element2 选择排在自己之后的所有符合条件的兄弟元素 [attribute] 用于选取带有指定属性的元素 [attribute*=value] 选取每个带有指定属性且值包含指定字符串的元素 [attributeI=value] 选取每个带有指定属性的元素,该元素的值等于指定字符串(比如 “en”)或 以该字符串后跟连接符作为开头的字符串(比如 “en-us”) [attribute$=value] 匹配属性值以指定值结尾的每个元素 [attribute^=value] 选择器选取每个带有指定属性且以指定字符串开头的元素。 [attribute=value] 用于选取属性值中包含指定词汇的元素例如选择test ——“title test”可以 而“titletest”不行 :first-child 用于选取属于其父元素的首个子元素的指定选择器 :first-of-type() 匹配元素是其父元素的第一个同类型子元素 :last-child 匹配属于其父元素的最后一个子元素的每个元素 :last-of-type() 匹配元素是其父元素的最后一个同类型子元素 :nth-child() 匹配属于其父元素的第 N 个子元素,不论元素的类型 :nth-last-child() 匹配属于其元素的第 N 个子元素的每个元素,不论元素的类型,从最后一个 子元素开始计数 :nth-last-of-type() 选择所有他们父级兄弟元素下具有相同的元素名 :nth-of-type 匹配属于父元素的特定类型的第 N 个子元素的每个元素 :only-child 匹配属于其父元素的唯一子元素的每个元素 :only-of-type 匹配属于其父元素的特定类型的唯一子元素 :checked 匹配每个已被选中的 input 元素(只用于单选按钮和复选框) :disabled 规定应该禁用 input 元素 :empty 匹配没有子元素(包括文本节点)的每个元素 :enabled 匹配每个启用的的元素(主要用于表单元素) :focus 用于选取获得焦点的元素

选择器(JQ & CSS)

说明

:not() 非匹配指定元素/选择器的每个元素

选择器

说明

:active 用于选择活动链接 :after 在被选元素的内容后面插入内容 :before 在被选元素的内容前面插入内容 :first-letter 用于选取指定选择器的首字母 :first-line 用于选取指定选择器的首行 :hover 用于标指针浮动在上面的选择鼠元素 :lang 用于选取带有以指定值开头的 lang 属性的元素 :link 用于选取未被访问的链接 :visited 用于选取已被访问的链接 :default :default伪类选择器只能作用在表单元素上,表示默认状态的表单元素。 :valid 用于匹配输入值为合法的元素 :invalid 用于匹配输入值为非法的元素 :in-range 匹配值在指定区间之内的input元素 :out-of- range 匹配值在指定区间之外的input元素 :require 用于匹配设置了 “required” 属性的元素 :read-only 用于匹配设置 “readonly”(只读)属性的元素 :read-write 用于匹配可读及可写的元素 :optional 用于匹配可选的输入元素 ::placeholder 用于控制表单输入框占位符的外观,它允许开发者/设计师改变文字占位符的样 式,默认的文字占位符为浅灰色。 ::selection 匹配被用户选取的选取是部分。只可以应用于少数的CSS属性:color, background, cursor,和outline。

2、css独有的选择器

3、jQuery特有

选择器

说明

[attribute!=value] 选取每个不带有指定属性和值的元素。 :text 选择器选取类型为 text 的元素。 :button 选择器选取类型为 button 的