前端面试题 :) 来源--知乎
vue —— 数据驱动视图
-
什么是vue生命周期
vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。这给了用户在不同阶段添加自己的代码的机会。在组件中具体的方法有:
beforeCreate
> 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建;在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。 不要在这个阶段使用data中的数据和methods中的方法!created
> data和methods都已经初始化OK,如要需要,最早可以再这个阶段操作beforeMount
> 执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂在到页面中mounted
> 表示vue实例已经初始化完成,此时组件脱离创建阶段,进入运行阶段,如果我们想要通过插件操作页面上的DOM节点,最早可以在这个阶段进行beforeUpdate
> data中数据已更新,页面还未同步updated
> 页面显示的数据和data中的数据已经保持同步activited
> keep-alive专属,组件被激活时调用deadctivated
> keep-alive专属,组件被销毁时调用beforeDestroy
> vue实例从运行阶段进入到会阶段, but此时所有的data和methods, 指令, 过滤器... 都还处于可用状态destroyed
> 此时所有的data, methods, 指令, 过滤器...都是处于不可用状态, 组件正式被销毁拓展: vue中内置方法, 属性和生命周期的运行顺序(methods、computed、data、watch、props)
data的初始化是在created时已经完成数据观测(data observe), 并且诸如
methods
、computed
、props
等都已经初始化
props -> methods -> data -> computed -> watch
-
vue生命周期的作用是什么
简单总结就是可以在生命周期的不同阶段调用对应的钩子函数
-
第一次页面加载会触发哪些钩子
beforeCreate,created,beforeMount,mounted
-
简述每个周期具体适合那些场景
beforeCreate
: loading事件, 在加载实例时触发created
: 初始化完成时的事件写在这里, 例如数据(异步)请求, 也可以在此结束loading事件mounted
: 挂载元素, 获取DOM节点updated
: 对数据统一处理, 在此写响应函数beforeDestroy
: 可以做阻断, 例如确认停止事件的确认框, 因为此时实例还未销毁 -
created和mounted的区别
created
: 在模板渲染成HTML前调用,即通常初始化某些属性值, 然后再渲染成视图mounted
: 在模板渲染成HTML后调用, 通常是初始化页面完成后, 在对HTML的DOM节点进行一些需要的操作(例如echart
这里的操作可以放在这里进行, 而不是created
里) -
vue获取数据在那个周期函数
一般建议放在
created
中, 如果有DOM操作就需要放在mounted
中 -
请详细说下你对vue生命周期的理解
简述生命周期的概念, 表明它可以让用户在对应的阶段进行需要的操作, 列举八大基础钩子, 也可以对常用的
created
和mounted
进行拓展补充
vue路由面试题
-
MVVM框架是什么
MVVM > Model-View-ViewModel, 也就是把MVC中的controller演变成ViewModel.
Model : 数据模型, 可以再Model中定义数据修改和操作的业务逻辑. 我们也可以称它为数据称, 因为它仅关注数据本身, 不关心任何行为
View : 用户操作界面(UI), 当ViewModel对Model进行更新的时候, 会通过数据绑定更新到View
ViewModel : 业务逻辑层, View需要什么数据, ViewModel要提供这个数据; View有某些操作, ViewModel就要对其响应, 所以, 也可以说它是 Model for View
总结 : MVVM模式简化了界面与业务的依赖, 解决了数据频繁更新. MVVM在使用当中, 利用双向绑定技术, 使得Model变化时, ViewModel会自动更新, 而ViewModel变化时, View也会自动变化
-
vue-router是什么? 它有哪些组件
它是vue官方推荐使用的路由框架. 路由跳转都需要vue-router. 它有三个基本的概念: route, routes, router
route
> 指一条路由, 由单词也可以看出来, 它是单数routes
> 指一组路由, 把route组合起来, 形成一个数组, 即为routesrouter
> 是一个机制, 相当于一个管理者, 它管理着路由. 因为routes只是定义了一组路由, 他放在哪里都是静止的, router的作用就是当用户点击路由对应的按钮时, 它会到routes中去查找, 从而实现页面上的跳转它有哪些组件?
<router-link :to='' active-class="active">//路由声明式跳转 ,active-class是标签被点击时的样式 <router-view> //渲染路由的容器 <keep-alive> //缓存组件
-
active-class是哪个组件的属性?
router-link
是用来做选中样式的切换
使用方式:
// 1. 直接在路由js文件中配置linkActiveClass export default new Router({ linkActiveClass: 'active' // 可以自定义类名~ }) // 2. 直接在router-link中写入active-class <router-link :to='' active-class="active">
-
怎么定义vue-router的动态路由?怎么获取传过来的值
两种方式 :
query
和params
基础用法 : 都可以通过this.$router.push 跳转
-
query :
// 点击事件中写法; 推荐用path this.$router.push({ path: 'detail', query: { id: '1' } }) // 用name也不报错 this.$router.push({ name: 'detail', query: { id: '1' } }) // router-link中写法 <router-link to='/detail?id=1'> handleToDetail </router-link> // 传参接收 this.pageId = this.$route.query.id // 注意此处为route // 注意: 若使用name跳转动态路由, 需要在router中配置route的 'name' 属性 /** router/index.js **/ { path: '/detail', name: 'detail', component: () => import('@/view/detail') }
-
params :
// 只能使用name this.$router.push({ name: 'detail', params: { id: '2' } }) // router-link中写法 <router-link to="/detail/" + item.id></router-link> // 或者 <router-link to="{name: 'test', params: { id: this.pageId }}"></router-link> // 接收参数 this.pageId = this.$route.params.id /** router/index.js **/ { path: '/detail/:id', // 容易出问题的地方, :xx 必须和传参时使用相同字段 name: 'detail', // 一定要设置name,才可以传params! component: ... }
区别 :
- query通过url传参, 没有也没关系, params是路由的一部分, 必须在路由后面添加参数名
- params是路由的一部分, 如果这个路由配置中要求params传参, 但是跳转的时候没有传这个参数, 就会导致失败或页面无内容
- query 使用path传参, params 使用name传参
- 二者传参的区别直白点可以理解为: query相当于get请求, 参数显示在地址栏; params相当于post请求, 参数不会在地址栏中显示
-
-
vue-router有哪几种导航钩子
vue-router的导航钩子又叫导航守卫;导航表示路由正在发生改变,vue-router提供的导航守卫主要用来:通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程:全局的,单个路由独享的,组件级的。
注意:参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察$route对象来应对这些变化,或使用beforeRouteUpdate的组件内导航
-
全局守卫: router.beforeEach
使用router.beforeEach 注册一个全局前置守卫
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { ... })
当一个导航触发时,全局前置守卫按照创建顺序调用. 守卫是异步解析执行, 此时导航在所有守卫resolve完之前一直处于等待中
每个守卫方法都接收三个参数
to: Route > 即将要进入的目标路由对象
from: Route > 当前导航正在离开的路由
next: Function > 一定要调用该方法来resolve这个钩子. 执行结果依赖next方法的调用参数
next()
: 进行管道中下一个钩子. 如果全部钩子都执行完了, 则导航的状态就是confirmed(确认的)next(false)
: 中断当前的导航. 如果浏览器的url改变了(可能是用户手动点击浏览器的后退按钮), 那么url地址会重置到from路由
对应的地址next( '/' )
或者next({ path: '/' })
: 跳转到一个不同的地址. 当前的导航被中断, 然后进行一个新的导航. 你可以向next传递任意位置对象
, 且允许设置诸如
replace: true, name: 'home' 之类的选项以及任何用在router-link
的to prop
或router.push
中的选项next(error)
: (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止
且该错误会被传递给router.onError()
注册过的回调。
-
全局解析守卫: router.beforeResolve
2.5.0 新增
在
2.5.0+
你可以用router.beforeResolve
注册一个全局守卫
。这和router.beforeEach
类似,区别是:
在导航被确认之前
,同时在所有组件内守卫
和异步路由组件
被解析之后
,解析守卫就被调用
。 -
全局后置钩子: router.afterEach
你也可以注册
全局后置钩子
,然而和守卫不同的是
,这些钩子不会接受 next 函数
也不会改变导航本身
:router.afterEach((to, from) => { // ... })
-
路由独享的守卫: beforeEnter
你可以在路由配置上直接定义
beforeEnter
守卫:const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
这些守卫
与全局前置守卫
的方法参数是一样的
。 -
组件内的守卫: beforeRouteEnter、beforeRouteUpdate(2.2新增)、beforeRouteLeave
最后,你可以在
路由组件内
直接定义以下路由导航守卫
:beforeRouteEnter
、beforeRouteUpdate
(2.2 新增) 、beforeRouteLeave
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, //不过,你可以通过传一个回调给 next来访问组件实例。 //在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。 beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 }) }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
注意:
beforeRouteEnter
是支持给next传递回调
的唯一守卫。对于beforeRouteUpdate
和beforeRouteLeave
来说,this
已经可用了,所以不支持传递回调
,因为没有必要了:beforeRouteUpdate (to, from, next) { // just use `this` this.name = to.params.name next() }
离开守卫beforeRouteLeave:
通常用来禁止用户在还未保存修改前突然离开。该导航可以通过next(false)
来取消:beforeRouteLeave (to, from , next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() } else { next(false) } }
-
-
route和router的区别
$router对象
-
$router 是全局路由的实例, 是router构造方法的实例
-
路由实例方法:
-
push :
// 字符串 this.$router.push('xxx') // 对象 this.$router.push({ path: 'xxx' }) // params this.$router.push({ name: 'xxx', params: { id: '1' } }) // query this.$router.push({ path: 'xxx', query: { id: '2' } })
注意:push方法的跳转会向history栈添加一个新的记录, 当我们点击浏览器的返回按钮时可以看到之前的页面
-
go :
页面路由跳转, 前进或者后退
this.$router.go(-1) // 后退1步 this.$router.go(1) // 前进1步
-
replact :
替换当前页面, 不会向history栈添加新纪录, 一般用来做404页面
-
$route对象
-
$route对象表示当前激活的路由对象, 包含了当前的路由信息: 当前的路径, 参数, query对象等等.
-
$route的属性
-
$route.path > 字符串,对应当前路由的路径,总是解析为绝对路径,如"/foo/bar"。
-
$route.params > 一个 key/value 对象,包含了 动态片段 和 全匹配片段, 如果没有路由参数,就是一个空对象。
-
$route.query > 一个 key/value 对象,表示 URL 查询参数。 例如,对于路径 /foo?user=1,则有$route.query.user == 1, 如果没有查询参数,则是个空对象。
-
$route.hash > 当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。
-
$route.fullPath > 完成解析后的 URL,包含查询参数和hash的完整路径。
-
$route.matched > 数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
-
$route.name > 当前路径名字
-
$route.meta > 路由元信息
-
-
-
vue-router传参
- 命名路由搭配params,刷新页面参数会丢失
- 查询参数搭配query,刷新页面数据不会丢失
- 接受参数使用this.$router后面就是搭配路由的名称就能获取到参数的值
-
vue-router的两种模式
-
一种是利用url的hash,就是通常所说的锚点#,javascript通过hashChange事件来监听url的变化,IE7以下需要轮询。
比如这个 URL:
http://www.abc.com/#/hello
,hash 的值为#/hello
。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。 -
另一种是HTML5的History模式,它使url看起来像普通网站那样,以“/”分割,没有#,单页面并没有跳转。不过使用这种模式需要服务端支持,服务端在接收到所有请求后,都只想同一个html文件,不然会出现404。因此单页面应用只有一个html,整个网站的内容都在这一个html里,通过js来处理。
history 模式利用了 HTML5 History Interface 中新增的
pushState()
和replaceState()
方法。(需要特定浏览器支持)
这两个方法应用于浏览器的历史记录栈,在当前已有的back
、forward
、go
的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
-
-
vue-router实现路由懒加载(动态加载路由)
懒加载: 也叫延迟加载,即在需要的时候进行加载,随用随载
推荐使用ES7的写法 —— import
component: () => import('@/components/profile')
vue常见面试题
-
vue的优点
Vue.js
是一个构建数据驱动的web界面的渐进式框架. Vue.js的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件. 核心是一个响应式的数据绑定系统.优点 : (这里也可以理解为SPA的好处)当前端和数据做一些操作的时候, 可以通过AJAX请求对后端做数据持久化, 不需要刷新整个页面, 只需要改动DOM里需要该懂得那部分数据. 特别是移动端应用场景下, 刷新页面太昂贵, 会重新加载很多资源, 虽然有些会被缓存, 但是页面DOM, JS, CSS都会被页面重新解析一遍, 因此移动端页面通常会做出SPA单页面应用; 此外从多方面列举, vue的优点 :
- MVVM框架 : 数据驱动视图
- 组件化(提高开发效率,方便复用,简化调试,提升项目可维护性,便于协同开发)
- 轻量、简洁、高效、快速(压缩之后20kb左右大小)
- 学习成本较其他(
Angular
,React
)低
那么vue的不足有哪些呢?
- vue不缺入门教程,可是很缺乏高阶教程&文档&书籍
- vue不支持IE8(这应该算是个优点吧..../汗)
- 生态环境差不如
Angular
和React
- 社区不大(网上听的)
-
vue父组件向子组件传递数据
使用props /** parent **/ <child :parentResult = 'result' /> // 标准写法其实是 :parent-result data() { result: { ... } } /** child **/ <div>{{ parentResult.xxx }}</div> props: { parentResult: { type: Object, default() { return {} } } } // 也可以调用子组件的方法传参, 不过实用性不高
-
子组件向父组件传递事件
概括:
- 子组件需要使用
this.$emit
将子组件的事件进行上级传递 - 父组件需要使用@事件名的方式, 接收子组件的事件
/** parent **/ <child @c-click = 'handleClick' /> // 自定义事件名与子组件发射的事件名统一 methods: { handleClick(arg) { console.log('父组件事件调用') } } /** child **/ <button @click = 'emitClick' /> methods: { emitClick() { this.$emit('c-click', arg) } }
- 子组件需要使用
-
v-show和v-if指令的共同点和不同点
二者都是用来控制元素的显示的
v-if
是真正的条件渲染, 因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建. 但同时它也是惰性的: 如果在初始渲染时条件为false, 则什么也不做, 直到条件第一次变为true, 才开始渲染条件块v-show
不管初始条件是什么, 元素总是会被渲染, 并只是简单的CSS进行切换来控制显示使用规则:
v-if
有更高的切换开销, 而v-show
有更高的初始渲染开销. 因此, 如果需要非常频换地切换元素显示, 那么使用v-show
更优, 如果是在运行时条件很少改变, 则使用v-if
较好 -
如何让CSS只在当前组件中起作用
style
标签上添加scoped
<style scoped> </style>
scoped
: 实现组件私有化, 不对全局造成样式污染 -
如何获取DOM
首先, 因为vue钩子函数每个阶段的特性, 获取DOM的操作不能直接放在
created
中, 如果要写在created
和mounted
中, 应写在this.nextTick()
的回调函数中-
可以直接使用原生js
document.getElementById()
, ... -
给标签中加上ref='dom', 然后在代码中this.$refs.dom就可以拿到页面元素
ref
绑定在一般元素上时,$refs
指向DOM元素, 绑定在组件上时,$refs
指向组件实例
-
-
说出几种vue的指令和它的用法
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
-
v-if :根据表达式的值来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是
<template>
,将提出它的内容作为条件块。当条件变化时该指令触发过渡效果。
当和
v-if
一起使用时,v-for
的优先级比v-if
更高。 -
v-else : 不需要表达式
限制:前一兄弟元素必须有
v-if
或v-else-if
。 -
v-else-if :表示
v-if
的“else if 块”。可以链式调用。限制:前一兄弟元素必须有
v-if
或v-else-if
-
v-show :根据表达式之真假值,切换元素的
display
。当条件变化时该指令触发过渡效果。
-
v-text :更新元素的
textContent
。如果要更新部分的textContent
,需要使用{{ Mustache }}
插值。 -
v-html :更新元素的
innerHTML
。注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。如果试图使用
v-html
组合模板,可以重新考虑是否通过使用组件来替代。在网站上动态渲染任意 HTML 是非常危险的,因为容易导致
XSS 攻击
。只在可信内容上使用v-html
,永不用在用户提交的内容上。在``单文件组件
里,
scoped的样式不会应用在
v-html` 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。 -
v-bind : 简写 --
:
; 绑定动态参数动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。
修饰符:
.prop
- 作为一个 DOM property 绑定而不是作为 attribute 绑定。.camel
- (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持).sync
(2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的v-on
侦听器。
-
v-on: 简写 --
@
; 绑定动态事件用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。
修饰符:
.stop
- 调用event.stopPropagation()
。.prevent
- 调用event.preventDefault()
。.capture
- 添加事件侦听器时使用 capture 模式。.self
- 只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyCode | keyAlias}
- 只当事件是从特定键触发时才触发回调。.native
- 监听组件根元素的原生事件。.once
- 只触发一次回调。.left
- (2.2.0) 只当点击鼠标左键时触发。.right
- (2.2.0) 只当点击鼠标右键时触发。.middle
- (2.2.0) 只当点击鼠标中键时触发。.passive
- (2.3.0) 以{ passive: true }
模式添加侦听器
-
v-for :基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法
alias in expression
,为当前遍历的元素提供别名:<div v-for="item in items"> {{ item.text }} </div>
另外也可以为数组索引指定别名 (或者用于对象的键):
<div v-for="(item, index) in items"></div> <div v-for="(val, key) in object"></div> <div v-for="(val, name, index) in object"></div>
-
v-model: 在表单控件或者组件上创建双向绑定。
修饰符:
.lazy
- 取代input
监听change
事件.number
- 输入字符串转为有效的数字.trim
- 输入首尾空格过滤
-
v-slot : 简写 --
#
提供具名插槽或需要接收 prop 的插槽。
<!-- 具名插槽 --> <base-layout> <template v-slot:header> Header content </template> Default slot content <template v-slot:footer> Footer content </template> </base-layout> <!-- 接收 prop 的具名插槽 --> <infinite-scroll> <template v-slot:item="slotProps"> <div class="item"> {{ slotProps.item.text }} </div> </template> </infinite-scroll> <!-- 接收 prop 的默认插槽,使用了解构 --> <mouse-position v-slot="{ x, y }"> Mouse position: {{ x }}, {{ y }} </mouse-position>
-
v-pre : 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
<span v-pre>{{ this will not be compiled }}</span>
-
v-cloak :这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如
[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。 -
v-once :只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
拓展 :Mustache语法: (双大括号) 的文本插值 --
{{ msg }}
; 每个绑定都只能包含单个表达式 -
-
vue-loader是什么? 使用它的用途有哪些?
简单的说,他就是基于webpack的一个的loader,解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理,核心的作用,就是提取,划重点。
至于什么是webpack的loader,其实就是用来打包、转译js或者css文件,简单的说就是把你写的代码转换成浏览器能识别的,还有一些打包、压缩的功能等。
vue-loader 的作用(引用自官网)
允许为 Vue 组件的每个部分使用其它的 webpack loader,例如在 style 的部分使用 Sass 和在 template 的部分使用 Pug;
允许在一个 .vue 文件中使用自定义块,并对其运用自定义的 loader 链;
使用 webpack loader 将 style 和 template 中引用的资源当作模块依赖来处理;
为每个组件模拟出 scoped CSS;
在开发过程中使用热重载来保持状态。 -
为什么使用key?
key
的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
最常见的用例是结合
v-for
:<ul> <li v-for="item in items" :key="item.id">...</li> </ul>
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
- 完整地触发组件的生命周期钩子
- 触发过渡
例如:
<transition> <span :key="text">{{ text }}</span> </transition>
当
text
发生改变时,<span>
总是会被替换而不是被修改,因此会触发过渡。 -
axios及安装
axios
是一个基于Promise的http库, 简单的讲就是可以发送get、post请求特性
- 可以在浏览器中发送
XMLHttpRequest
- 可以在node.js发送http请求
- 支持PromiseAPI
- 拦截请求和响应
- 转换请求数据和响应数据
- 能够取消请求
- 自动转换json数据
- 客户端支持保护安全免受XSRF攻击
安装
// 安装模块 npm install axios --save
使用
<!-- 直接script标签应用 --> <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
// ES6 import引用 import axios from 'axios' // 如果要全局使用axios就要在main.js中将其加载到Vue的原型上 /** main.js **/ Vue.prototype.$axios = axios
- 可以在浏览器中发送
-
axios解决跨域
跨域
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
跨域配置 cli-3+ 使用
proxy
配置/** vue.config.js **/ module.exports = { devServer: { proxy: { '/api': { target: 'https://www.xx.com', // 目标路径 changeOrigin: true, // 是否跨域 ws: true, pathRewrite: { '^/api': '' // 重写路径 } } } } }
-
v-modal的使用
v-model是用来对表单元素中input、textarea、select这些标签进行双向绑定的,它会根绝空间类型自动选取正确的方法来更新元素。
它本质上是一个语法糖。
<input v-model="test" /> // 等价于 <input :value="test" @input="test = $event.target.value" />
在input不同组件中的应用
- 在复选框中使用时,
v-model
在data中应该由数组与其对应 - 在单选框、复选框、或是下拉框中,要为选项例如
<option>
设置value
属性
v-model的修饰符
.lazy
失去焦点时触发事件.trim
清除前后空格.number
限制当前输入格式为数字类型
- 在复选框中使用时,
-
scss的安装及使用
在
Vue-CLI
中, 首先要安装sass
依赖:npm install node-sass --save-dev npm install sass-loader --save-dev
在项目(组件)中使用:
<style lang="scss" scoped> To Do Something </style>
(待完善; 答非Vue-CLI中, sass的安装, 使用, 规范更好)
-
请说出vue-cli项目中src目录中每个文件夹和文件的用法
满配(
vue-router
,vuex
)自带的:- assets 存放静态资源
- components 组件文件夹
- router 路由文件夹, 定义路由相关的配置
- store vuex文件夹
- views 视图(路由对应的页面所在)文件夹
- App.vue 根组件
- main.js 入口文件
项目规范中"潜规则"文件夹:
- api/network/serve/http 网络请求文件夹(如果将请求封装统一管理)
- style 样式文件夹
- mixin "混入"文件夹
- utils 工具方法文件夹(例如过滤器, 全局方法, 全局变量)
- icons 项目所用icon文件夹(看需求和习惯)
-
分别简述computed和watch的使用场景
二者有明显的区别:
watch
中的函数是不需要调用的computed
内部的函数调用的时候不需要加()watch
属性监听, 监听属性的变化computed
计算属性, 通过属性计算而得来的属性watch
需要在数据变化时执行异步或开销较大的操作时使用对于任何复杂逻辑或一个数据属性在它所依赖的属性发生变化时, 也要发生变化, 这种情况下, 推荐使用
computed
computed
属性的结果会被缓存(不同于methods
), 除非以来的响应式属性变化才会重新计算. 主要当做属性来使用;computed
中的函数必须用return
返回最终的结果watch
(监听)一个对象, 键是需要观察的表达式, 值是对应的毁掉函数. 主要用来监听某些特定数据的变化, 从而进行某些具体的业务逻辑操作所以二者的使用场景也不同:
computed 当一个属性受多个属性影响时, 就需要用到
computed
最典型的例子: 购物车商品结算时的价格计算
watch 当一条数据影响多条数据的时候就需要用
watch
搜索数据
-
v-on可以监听多个方法吗
可以
<input type="text" v-on="{ input: handleInput, focus: handleFocus, blur: handleBlur }" />
-
$nextTick的使用
this.$nextTick()
将回调延迟到下次DOM
更新循环之后执行. 在修改数据之后立即使用它, 然后等待DOM
更新. 它跟全局方法Vue.nextTick一样, 不同的是会掉的this
自动绑定到调用它的实例上.this.$nextTick()
在页面交互, 尤其是从后台获取数据后重新生成DOM
对象之后的操作有很大优势, 举一个简单的例子: 在钩子函数created
执行的时候DOM
其实并未进行任何渲染, 而此时进行DOM
操作并无作用, 而在created
中使用this.$nextTick()
可以等待DOM
生成以后再来获取DOM
对象 -
vue组件中data为什么必须是一个函数
因为对于组件来说有一个很明显的特性石在于它是可以被复用的, 所以只有组件的
data
是一个函数的时候, 每一个实例的data
才是独立的(每个实例可以维护一份被返回对象的独立的拷贝), 就不会互相影响. 这是因为js本身的特性带来的, 跟vue
本身设计无关 -
vue事件对象的使用
事件对象就是指
event
对象, 在vue
中, 绑定事件时, 可以有小括号, 也可以没有-
在绑定事件时, 如果没有小括号, name第一个参数就是事件对象
-
如果有小括号, 但是没有参数, 那么
e
默认就是undefined
-
如果需要事件对象, 并且需要传参, 那么需要在绑定时使用
$event
进行占位<input type="text" @keyup.13="fn($event, 100)" />
-
-
组件间的通信
组件可以有以下几种关系:
如上图所示: A和B、B和C、B和D都是父子关系,C和D是兄弟关系,A和C是隔代关系(可能隔多代)
组件间的通信方式(六种) :
-
props
/$emit
父组件向子组件传值 : 父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
子组件向父组件传值(通过事件形式): 子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
-
$emit
/$on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。
具体实现方式:
let Event=new Vue(); Event.$emit(事件名,数据); Event.$on(事件名,data => {});
$on
监听了自定义事件 data-a和data-b,因为有时不确定何时会触发事件,一般会在 mounted 或 created 钩子中来监听。 -
vuex
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
-
$attrs
/$listeners
多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法----
$attrs
/$listeners
$attrs
:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。$listeners
:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件
-
provide
/inject
Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的----vue官方文档
-
$parent
/$children
与ref
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例$parent
/$children
:访问父 / 子实例
需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。
总结
常见使用场景可以分为三类:
- 父子通信:
父向子传递数据是通过 props,子向父是通过 events(
$emit
);通过父链 / 子链也可以通信($parent
/$children
);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners
- 兄弟通信:
Bus;Vuex
- 跨级通信:
Bus;Vuex;provide / inject API、
$attrs/$listeners
还有个插槽传值
- 插槽之间的传值,插槽要显示的内容是写在父组件中的,也就是父组件中的数据是写在自己的组件里。
- 而父子组件之间的传值,是在当前组件拿到了数据之后,然后才在当自己的组件中显示。
- 如果说他们之间有什么联系的话,插槽传值,其实类似于父组件向子组件传值。而插槽默认值的写法又像是子组件向父组件传值,只是如果父组件有传值过来,会被覆盖掉了而已。
-
-
渐进式框架的理解
就是一开始不需要你完全掌握它的全部功能特性,可以后续逐步增加功能。没有多做职责之外的事情
Vue与React、Angular的不同是,但它是渐进的
-
vue.js只提供了vue-cli生态中最核心的组件系统和双向数据绑定
-
就好像 vuex、vue-router都属于围绕vue.js开发的库
使用Angular,必须接受以下东西
- 必须使用它的模块机制
- 必须使用它的依赖注入
- 必须使用它的特殊形式定义组件
所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰
使用React,你必须理解
- 函数式编程的理念
- 需要知道它的副作用
- 什么是纯函数
- 如何隔离、避免副作用
它的侵入性看似没有Angular那么强,主要因为它是属于软性侵入的
参考资料 :
-
-
vue中双向数据绑定是如何实现的
所谓双向数据绑定, 无非就是数据层和视图层中的数据同步, 在写入数据时视图层实时的跟着更新
实现mvvm的双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
- 实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
- 实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
- 实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
- mvvm入口函数,整合以上三者
getter函数里面执行的任务就是watcher订阅者, 而setter函数执行的任务就是发布者; 相信很多人看过了这个也是一知半解, 下面我来解释一波:
ECMAScript中有两种属性: 数据属性和访问器属性, 数据属性一般用于存储数据数值, 访问器属性对应的是set/get操作, 不能直接存储数据值, 每种属性下面又都含有四个特性.下面介绍一下:
数据属性
1.[[Configurable]]: 表示能否通过delete将属性删除,能否把属性修改为访问器属性, 默认为false。当把属性Configurable设置为false后,该属性不能通过delete删除,并且也无法再将该属性的Configurable设置回true
2.[[Enumerable]]: 表示属性可否被枚举(即是否可以通过for in循环返回),默认false
3.[[Writable]]: 表示属性是否可写(即是否可以修改属性的值),默认false
4.[[Value]]: 该属性的数据值, 默认是undefined访问器属性
1.[[Configurable]]: 表示能否通过delete将属性删除,能否把属性修改为数据属性, 默认为false。当把属性Configurable设置为false后,该属性不能通过delete删除,并且也无法再将该属性的Configurable设置回true
2.[[Enumerable]]: 表示属性可否被枚举(即是否可以通过for in循环返回),默认false
3.[[Get]]: 读取属性时调用的函数, 默认为undefined
4.[[Set]]: 写入属性时调用的函数, 默认是undefined在修改属性的特性或者定义访问器属性的时候, 需要借助ECMAScript 5中的一个方法: Object.defineProperty(), 这个方法接收三个参数: 属性所在对象, 属性的名字, 描述符对象; 为对象定义多个属性的话, 就用函数的复数写法:Object.defineProperties();
那么通过这个ES5的方法就可以直接很简单粗暴的说明双向绑定的原理:
<input type="text" id="inp" /> <div id="box"></div> <script> let obj = {}; let oInp = document.getElementById('inp'); let oBox = document.getElementById('box'); Object.defineProperty(obj, 'name', { configurable: true, enumerable: true, get: function() { console.log(111) return val; }, set: function(newVal) { oInp.value = newVal; oBox.innerHTML = newVal; } }); oInp.addEventListener('input', function(e) { obj.name = e.target.value; }); obj.name = 'xx';
那么实现数据双向绑定的核心就是利用为每一个属性都创建了订阅者的实例对象, 以便观察, getter函数里面返回一个value值,在setter函数中写入修改后的值并调用update方法更新视图的数据值, Configurable和Enumerable这两个特性描述符默认是true, 因此不用写
function defineReactive (obj, key, val) { var dep = new Dep(); //这是一个构造函数 其原型是为属性添加订阅者 Object.defineProperty(obj, key, { get: function() { if(Dep.target) { dep.addSub(Dep.target); //添加订阅者到Dep实例对象 } return val; // 返回监听到的value值 }, set: function (newVal) { if(newVal === val) return; val = newVal; // 写入新的value值 dep.notify(); // 作为发布者发出通知 然后dep会迭代调用各自的update方法来更新视图 } }); } function observe(obj, vm) { Object.keys(obj).forEach(function(key) { defineReactive(vm, key, obj[key]); }); }
-
单页面应用和多页面应用区别及优缺点
单页面应用(SinglePage Web Application,SPA)
通俗一点说就是指只有一个主页面的应用, 浏览器一开始要加载所有必须的html, js, css. 所有的页面内部都包含在这个所谓的主页面中. 但在codeing的时候,还是会分开写, 然后在交互的时候由路由程序动态载入, 单页面的页面跳转, 仅刷新局部资源. 多用于pc端官网, 购物等网站
多页面(MultiPage Application,MPA)
就是指一个应用中有多个页面, 页面跳转时是整页刷新, 多用于app或客户端等
具体对比分析
单页面应用(SinglePage Web Application,SPA) 多页面应用(MultiPage Application,MPA) 组成 一个外壳页面和多个页面片段组成 多个完整页面构成 资源共用(css,js) 共用,只需在外壳部分加载 不共用,每个页面都需要加载 刷新方式 页面局部刷新或更改 整页刷新 url 模式 a.com/#/pageone a.com/#/pagetwo a.com/pageone.html a.com/pagetwo.html 用户体验 页面片段间的切换快,用户体验良好 页面切换加载缓慢,流畅度不够,用户体验比较差 转场动画 容易实现 无法实现 数据传递 容易 依赖 url传参、或者cookie 、localStorage等 搜索引擎优化(SEO) 需要单独方案、实现较为困难、不利于SEO检索 可利用服务器端渲染(SSR)优化 实现方法简易 试用范围 高要求的体验度、追求界面流畅的应用 适用于追求高度支持搜索引擎的应用 开发成本 较高,常需借助专业的框架 较低 ,但页面重复代码多 维护成本 相对容易 相对复杂 单页面的优点
- 用户体验好, 快, 内容的改变不许要重新加载整个页面, 基于这一点
SPA
对服务器压力较小 - 前后端分离
- 页面效果会比较炫酷(比如切换页面内容时的过场动画)
单页面的缺点
-
不利于
SEO
-
导航不可用, 如果一定要导航需要自行实现前进、后退(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理)
-
初次加载开销耗时多
-
页面复杂度高
- 用户体验好, 快, 内容的改变不许要重新加载整个页面, 基于这一点
-
vue中过滤器有什么作用及详解
过滤器是一个通过输入数据,能够及时对数据进行处理并返回一个数据结果的简单函数。Vue有很多很便利的过滤器,可以参考官方文档,http://cn.vuejs.org/api/#过滤器,过滤器通常会使用管道标志 “ | ”, 比如:
{{ msg | uppercase }} // 'abc' => 'ABC'
-
v-if和v-for的优先级
当
v-for
和v-if
一起使用时,v-for
的优先级比v-if
更高 -
assets和static的区别
相同点: 资源在
html
中使用, 都是可以的区别: 使用
assets
下面的资源, 在js
中使用的话, 路径要经过webpack
中file-loader
编译, 路径不能直接写.assets
中的文件会经过webpack
打包, 重新编译, 推荐该方式. 而static
中的文件, 不会经过编译. 项目在经过打包后, 会生成dist
文件夹,static
中的文件只是复制一遍而已. 简单来说,static
中建议放一些外部第三方, 自己的放在assets
, 别人的放在static
中.注意 : 如果把图片放在
assets
与static
中, html页面可以使用; 但在动态绑定中,assets
路径的图片会加载失败, 因为webpack
使用的是commonJS
规范, 必须使用require
才可以 -
列举常用的指令
{{ msg }} 大胡子(
Mustache
)插值语法v-bind 动态属性绑定
v-on 动态事件绑定
v-model (表单)双向绑定
v-for 列表渲染(需提供
key
)v-show 根据条件表达式控制元素展示/隐藏
v-if 根据条件表达式控制元素是否渲染
-
vue常用的修饰符
- v-model修饰符
- .lazy 失去焦点才更新数据
- .trim 去除首尾空格
- .number 限制录入的为数字(可以输字母, 但是不显示)
- v-on修饰符
- .stop 组织事件冒泡, 相当于调用了
event.stopPropagation()
- .prevent 阻止默认行为, 详单与调用了
event.preventDefault()
, 比如表单提交,<a>
标签 - .once 事件只触发一次
- .stop 组织事件冒泡, 相当于调用了
- v-model修饰符
-
数组更新检测
vue
包含两种观察数组的方法-
变异方法
调用后原始数组改变, 从而触发视图更新
push | pop | shift | unshift | splice | sort | reverse
-
非变异方法
调用后不会改变原始数组, 总是返回一个新数组
filter | concat | slice
解决: 可以使用新数组替换旧数组
由于JS限制, vue不能检测一下变动的数组:
- 当你利用索引直接设置一个项时, 例如:
vm.items[index] = newValue
- 当你修改数组的长度时, 例如:
vm.items.length = newLength
vue
针对这两个问题给出了相应的解决方法, 使用这两种方法, 也会触发状态更新1. 使用`vue`全局方法: Vue.set() 或者使用`vm.$set()`实例方法 2. 使用`splice`, `concat`等修改数组
-
-
vue.set视图更新
Vue.set(target, key, value)
target: 要更改的数据源(可以使对象或者数组)
key: 要更改的具体数据
value: 重新赋的值
data() { return { items: [ { message: "test1" }, { message: "test2" } ] } }, methods: { handleClick() { Vue.set(this.items, 0, { message: "newTest" }) } }
总结: 如果实例创建之后添加新的属性到实例上, 它不会触发视图更新; 数据发生变化视图不更新, 那就要使用Vue.set方法来设置
-
自定义指令详解
全局注册
// 注册一个全局自定义指令 -- "v-focus" Vue.directive('focus', { // 当被绑定的元素插入到DOM中时 inserted: function (el) { el.focus() } })
局部注册
directives: { focus: { inserted: function (el) { el.focus() } } }
-
vue的两个核心点
-
数据驱动
在vue中, 数据的改变会
-
组件
组件化开发, 有点很多, 可以很好的降低数据之间的耦合度. 将常用的代码封装成组件之后, 就能高度的复用, 提高代码的可重用性. 一个页面/模块可以由多个组件所组成.
-
-
vue和JQuery的区别
- jQuery是使用选择器(
$
)选取DOM
对象, 对其进行赋值、取值、事件绑定等操作, 其实和原生的html
的区别只在于可以更方便的选取和操作DOM
对象, 而数据和界面是在一起的. - vue则是通过
Vue
对象将数据和View
完全分离开来了. 对数据进行操作不再需要引用响应的DOM
对象, 可以说数据和View
是分离的, 通过Vue
对象实现相互的绑定, 这就是MVVM
.
从编写习惯和规范上来说我认为是声明式(函数式)编程 和 命令式编程的区别
- jQuery是使用选择器(
-
引用组件的步骤
// 1. 引入组件 import NormalComps from '@/components/NormalComps' // 2. 注册组件 ... components: { NormalComps }, ...
<!-- 3. 使用组件 --> ... <normal-comps></normal-comps> ...
-
vue-cli打包命令是什么?打包后会导致路径问题,应该在哪里修改
npm run build
建立
vue.config.js
... module.exports = { publicPath: './', ... // outputDir: 'dist', // assetsDir: 'static' } ...
-
三大框架的对比
React
框架是起源于Facebook
的项目, 可以轻易的解决跨浏览器兼容的问题, 主要是通过对DOM
的模拟减少与DOM
的交互做到的.React
的模块化把组件进行了隔离, 出现问题的时候更方便程序员对其进行修改, 而且由于JavaScript
, 因策更有利于搜索引擎的优化.(能记多少是多少, 没屌用)特性:
- 声明式设计 :
React
采用声明范式, 可以轻松描述应用 - 高效 :
React
通过对DOM
的模拟, 最大限度的减少与DOM
的交互 - 灵活 :
React
可以与已知的库或框架很好地配合
优点:
- 速度快 : 在UI渲染过程中,
React
通过在虚拟DOM
中的微操作来实现对实际DOM
的局部更新 - 跨浏览器兼容 :
虚拟DOM
帮助我们解决了跨浏览器问题, 它为我们提供了标准化的API
, 甚至在IE8
中也是没问题的 - 模块化 : 为你程序编写独立的模块化UI组件, 这样当某个或某些组件出现问题时, 可以方便地进行隔离
- 单向数据流 :
Flux
是一个用在JavaScript
应用中创建单向数据层的架构, 它随着React
视图库的开发而被Facebook
概念化 - 同构、纯粹的
JavaScript
: 因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript
的执行, 预渲染你的应用有助于搜索引擎优化 - 兼容性好 : 比如使用
RequireJS
来加载和打包, 而Browserify
和Webpack
适用于构建大型应用, 他们那些艰难的任务不在让人望而生畏
缺点:
React
本身只是一个V
而已(MVC
中的V
), 并不是一个完整的框架, 所以如果是大型项目想要一套完整的框架的话, 基本都需要加上ReactRouter
和Flux
才能写大型应用.Vue
是尤雨溪(牛逼)编写的一个构建数据驱动的web界面的库, 准确来说不是一个框架, 他聚焦在V
(view)视图层特性:
- 轻量级的框架
- 双向数据绑定
- 指令
- 插件化
优点:
- 简单 : 官方文档清晰, 较
Angular
更简单易学 - 快速 : 异步批处理方式更新
DOM
- 组合 : 用解耦的、可复用的组件组合你的应用程序
- 紧凑 : ~18kb min+gzip, 且无依赖
- 强大 : 表达式, 无需声明依赖的可推导属性(
computed properties
) - 对模块友好 : 可以通过
NPM
、yarn
安装, 不强迫你所有的代码都遵循Angular
的各种规定, 使用场景更加灵活
缺点:
- 新生儿 : 对比
React
和Angular
, 略显年轻 - 影响不是很大(... ???) : Google有关
Vue.js
多样性或者说丰富性少于其他一些有名的库 - 不支持IE8(这也算缺点?)
Angular
是有一款优秀的前端框架, 已经被用于Google
的多款产品当中特性:
- 良好的应用程序结构
- 双向数据绑定
- 指令
- HTML模板
- 可嵌入、注入和测试
优点:
- 模板功能强大丰富, 自带了集齐丰富的
Angular
指令 - 是一个比较完善的前端框架, 包好服务, 模板, 数据双向绑定, 模块化, 路由, 过滤器, 依赖注入等所有功能
- 自定义指令, 自定义指令后可以在项目中多次使用
ng
模块化比较大胆的引入了Java
的一些东西(依赖注入), 能够很容易的写出可复用的代码, 对于敏感开发的团队来说非常用帮助Angular
是由互联网巨人谷歌开发, 这意味着它有一个坚实的基础和社区支持
缺点:
- 学习成本较高
- 验证功能错误信息显示比较薄弱, 需要很多模板标签
ngView
只能有一个, 不能嵌套多个视图- 比较笨重, 没有让用户选择一个轻量级的版本
- 声明式设计 :
-
跨组件双向数据绑定
好难整理
-
delete和vue.delete删除数据的区别
delete只是被删除的元素变成了
empty
/undefined
, 其他的元素的键值还是不变Vue.delete直接删除了数组, 改变了数组的键值(splice 也是)
let a = [1, 2, 3, 4] let b = [1, 2, 3, 4] delete a[1] console.log(a) this.$delete(b, 1) console.log(b)
结果 :
-
SPA首屏加载慢如何解决
单页面应用的好处在于一次载入所有页面资源, 利用本地计算能力渲染页面, 提高页面切换速度与用户体验. 但缺点在于所有页面资源将被一次性下载完, 此时封装出来的静态资源包体积较大, 使得第一次打开SPA页面时候需要的载入时间较长.
- 将公用的
js
库用script
标签引入(CDN
), 然浏览器并行下载资源 - 配置路由, 组件, 页面. 使用
懒加载
, 在调用某个组件时, 再下载某个js - 首屏loading图, 可以提高用户体验
- 将公用的
-
vue-router跳转和location.href有什么区别
-
vue slot
-
你们vue项目是打包了一个js文件,一个css文件,还是多个文件?
-
router-link在电脑上有用,在安卓上没反应怎么解决?
-
router-link在IE和Firefox中不起左右(路由不跳转)的问题
-
axios的她点有哪些
-
请说下封装vue组件的过程
-
vue各种组建通信方法
-
params和query的区别
-
vue mock
-
vue封装通用组件
-
vue初始化页面山东问题
-
vue禁止弹窗后的屏幕滚动
-
vue更新数组时触发视图更新的方法
-
vue常用的UI组件库
-
vue如何引进本地背景图片
-
vue如何引进sass
-
vue修改打包后静态资源路径的修改
vuex常见面试题
- vuex是什么?怎么使用?哪种功能场景使用它?
- vuex有哪几种属性?
- 不适用vuex会带来什么问题
- vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?
- vuex中如何一步修改状态
- vuex中actions和mutaions的区别
vue项目实战
- 顶部悬停效果
- 电话本列表效果(右边祖母分类,上下滑动,旁边字母显示高亮)
- vue做代理
- vue路由切换时的左滑和优化效果示例
react
react生命周期面试题
- react生命周期函数
- react生命周期中,最适合与服务端进行数据交互的是哪个函数
- 运行阶段生命周期调用顺序
- shouldComponentUpdate是做什么的(react性能优化是哪个周期函数)
- 指出(组件)生命周期方法的不同
react基础面试题
- react中keys的作用
- react中refs的作用
- react中三种构建组件的方式
- 调用setState之后发生了什么?
- react diff原理
- 为什么建议传递给setState的参数是一个callback而不是一个对象
- 除了在构造函数中绑定this,还有其他方式吗
- setState第二个参数的作用
- (在构造函数中)调用super(props)的目的是什么
- 件数flux思想
- 在react当中element 和 component 有什么区别
- 描述事件在react中的处理方式
- createElement和cloneElement有什么区别?
- 如何告诉react它应该编译生产环境版本
- controlled Component 与 Uncontrolled Component 之间的区别是什么
react组件面试题
- 展示组件(Presentational component)和容器组件(Container component)之间有何不同
- 类组件(Class component)和函数式组件(Functional component)之间有何不同
- (组件的)状态(state)和属性(props)之间有何不同
- 何为受控组件(controlled component)
- 何为高阶组件(higher order component)
- 应该在React组件的何处发起ajax请求
- react中组件传值
- 什么时候在功能组件(Class Component)上使用类组件(Functional Component)?
- 受控组件(controlled component)与不受控制的组件(Uncontrolled component)有什么区别?
- react组件的划分业务组件、技术组件?
redux面试题
- redux中间件
- redux有什么缺点
- 简单说一下redux
react性能比较面试题
- vue和react的区别
- react性能优化的方案
- react项目用过什么脚手架
- 介绍一下webpack
- 为什么我们需要使用react提供的children API而不是JavaScript的map?
JS
-
简述同步和异步的区别
在js编程中有两种思想: 同步, 异步. 有些人会分不清什么是同步和异步
想要分清它们, 我们首先要知道js的特性--单线程. 所谓单线程就是: 在没有完成这件事情的之前不会去做下一件事情.
那么同步就好理解了. 上件事情没完成, 就继续做上件事情, 等上件事情完成后才会去做下一件事情, js的大部分编程都是同步的
异步就完全不同了, 每个任务都有一个或多个毁掉函数(callback), 上一个任务执行完成后, 不是立刻执行下一个任务, 而是执行毁掉函数, 后一个任务则是不等前一个任务结束就执行, 所以程序的执行顺序与任务的排列顺序是不一致的(异步的), 异步是可以提高执行效率的
异步的运行机制:
- 所有同步任务都在主线程上执行, 形成一个执行栈(execution context stack)
- 主线程之外, 还存在一个"任务队列"(task queue). 只要异步任务有了运行结果, 就在"任务队列"之中放置一个事件
- 一旦"执行栈"中的所有同步任务执行完毕, 系统就会读取"任务队列", 看看里面有那些事件, 哪些对应的异步任务, 于是结束等待状态, 进入执行栈, 开始执行.
- 主线程不断重复上面的第三步
同步
和异步
本身是相对的同步就相当于是: 当客户端发送请求给服务端, 在等待服务端响应的请求时, 客户端不做其他的事情, 要等待服务端响应, 这会导致客户端要一直等待
异步: 当客户端发送服务端请求时, 在等待响应的同时, 客户端可以做其他的事情
-
怎么添加、移除、复制、创建和查找节点
-
实现一个函数clone可以对JavaScript中的五种主要数据类型(Number、String、Object、Array、Boolean)进行复制
-
如何消除一个数组中重复的元素
-
写一个返回闭包的函数
-
使用递归完成1到100的累加
-
JavaScript有哪几种数据类型
-
如何判断数据类型
-
console.log(1 + '2')和console.log(1 - '2')的打印结果
-
JS的事件委托是什么,原理是什么
-
如何改变函数内部的this指针的只想
-
列举集中解决跨域问题的方式,且说明原理
-
谈谈垃圾回收机制的方式及内存管理
-
写一个function, 清除字符串前后的空格
-
JS事项集成的方法有哪些
-
判断一个变量是否是数组, 有哪些办法
-
箭头函数与普通函数有什么区别
-
随机取1 - 10之间的证书
-
new 操作符具体干了什么
-
ajax原理
-
模块化开发怎么做
-
异步加载JS的方式有哪些
-
xml和json的区别
-
webpack如何实现打包
-
常见web安全及防护原理
-
用过哪些设计模式
-
为什么要有同源限制
-
offsetWidth/offsetHeight, clientWidth/clientHeight与scrollWidth/scrollHeight的区别
-
JavaScript有哪些方法定义对象
-
谈谈你对AMD, CMD的裂解
-
web开发中回话跟中的方法有哪些
-
介绍js有哪些内置对象
-
说几条写JavaScript的基本规范
-
eval是做什么的
-
null, undefined 的区别
-
["1", "2", "3"].map(parseInt) 打印是多少
-
JavaScript代码中的"use strict"
-
js延迟加载的方式有哪些?
-
defer和async
-
说说严格模式的限制
-
attribute和property的区别是什么?
-
ECMAScript6 class
-
常见兼容性问题
-
函数防抖节流
-
原始类型有哪几种?null是对象吗
-
为什么console.log(0.2 + 0.1 == 0.3) // false
-
说一下js中类型转换的规则
-
深拷贝和浅拷贝的区别?如何实现
-
如何判断this?箭头函数的this是什么
-
== 和 === 的区别
-
什么是闭包
-
JavaScript原型, 原型链
-
typeof() 和 instanceof() 的用法区别
-
什么是变量提升
-
all、apply以及bind函数内部实现是什么样的
-
为什么会出现setTimeout倒计时误差?如何减少
-
谈谈你对JS执行上下文栈和作用域链的理解
-
new的原理, 通过new 的方式创建对象和通过字面量创建有什么区别
-
prototype和proto区别是什么?
-
使用ES5实现一个继承
-
取数组的最大值(ES5, ES6)
-
ES6新的特性有哪些?
-
Promise有几种状态, Promise 有什么优缺点?
-
Promise构造函数是同步还是异步执行, then呢?Promise如何实现then处理?
-
Promise和setTimeout的区别
-
如何实现Promise.all?
-
如何实现Promise.finally?
-
如何判断img加载完成
-
如何组织冒泡
-
如何组织默认事件
-
ajax请求时,如何解析json数据
-
json和jsonp的区别
-
如何用原生js给一个按钮绑定两个onclick事件
-
拖拽会用到那些事件
-
document.write和innerHTML的区别
-
jQuery的事件委托方法bind, live, delegate, on之间有什么区别?
-
浏览器是如何渲染页面的
-
$(document).ready()方法和window.onload有什么区别
-
jQuery中.get()提交和post()提交有区别吗
-
对前端路由的理解? 前后端路由的区别
-
手写一个类的继承
-
XMLHttpRequest: XMLHttpRequest.readyState 状态码的意思
正则表达式常见面试题
- 建一个字符串: get-element-by-id转化为驼峰形势
- 匹配二进制数字
- 非零的十进制数字(有至少一位数字,但是不能以0开头)
- 匹配一年中的12个月
- 匹配常见的固定电话号码
- 匹配ip地址
- 匹配用尖括号括起来的以a开头的字符串
- 分割数字每三个以一个逗号划分
- 判断字符串是否包含数字
- 判断电话号码
- 判断是否符合指定格式
- 判断是否符合USD格式
- JS实现千位分隔符
- 获取url参数
- 验证邮箱
- 验证身份证号码
- 匹配汉字
- 去除首尾的'/'
- 判断日期格式是否符合'yyyy-MM-dd'的形式,简单判断,只判断格式
- 判断日期格式是否符合'yyyy-MM-dd'的形式,严格判断
- IPv4地址正则
- 十六进制颜色正则
- 车牌号正则
- 过滤HTML标签
- 密码强度正则, 最少6位,包括至少一个大写字母,一个小写字母,一个数字,一个特殊字符
- 匹配浮点数
浏览器/HTML/CSS面试题
- 什么是盒模型
- 行内元素有哪些?块级元素有哪些?空(void)元素有哪些?行内元素和块级元素有什么区别?
- 简述src和href的区别
- 什么css Hack
- 优雅降级 和 渐进增强
- px和em的区别
- Http的状态码有哪些
- 一次完整的HTTP请求是怎么一个过程
- HTTPS是如何实现加密的
- 浏览器是如何渲染页面的
- 浏览器的内核? 分别有什么代表的浏览器
- 页面导入时,使用link和@import有什么区别
- 如何优化图像,图像格式的区别
- 列举你了解HTML5, CSS3的新特性
- 可以通过哪些方法优化css3 animation渲染
- 列举几个前端性能方面的优化
- 如何实现同一个浏览器多个标签页之间的通信
- 浏览器的存储技术有哪些
- css定位方式
- 尽可能多的写出浏览器兼容性问题
- 垂直上下居中的方法
- 响应式布局原理
- 清除浮动的方法
- http协议和tcp协议
- 刷新页面,js请求一般会有哪些地方有缓存处理
- 如何对网站的文件和资源进行优化
- 你对网页标准和W3C重要性的理解
- http和https的区别
- data-属性的作用
- 如何让Chrome浏览器显示小于12px的文字
- 那些操作会引起页面回流(Reflow)
- CSS预处理器的比较: less, sass
- 如何实现页面每次打开时清除本页缓存
- 什么事Virtual DOM,为何要使用Virtual DOM
- 伪元素和伪类的区别
- http的集中请求方法和区别
- 前端需要注意哪些SEO
- img的title和alt有什么区别
- 从浏览器地址输入url到显示页面的过程发生了什么
- 如何进行网站性能优化
- 语义化的理解
- HTML5的离线存储怎么使用,工作原理能不能解释一下
- 浏览器是怎么对HTML5的离线存储资源进行管理和加载的呢
- iframe有哪些缺点
- web标准以及W3C标准是什么
- DOCTYPE的作用,严格模式与混杂模式如何区分?他们有何意义
- HTML全局属性(global attribute)有哪些
- Canvas和SVG有什么区别
- 如何在页面上实现一个圆形的可点击区域
- 网页验证码是干嘛的,是为了解决什么安全问题
- 请描述一下cookies, sessionStorage和localStorage的区别
- CSS选择器有哪些?那些属性可以继承
- CSS优先级算法如何计算
- CSS3有哪些新特性
- 请解释一下CSS3的flexbox(弹性盒布局模型),以及使用场景?
- 用纯CSS创建一个三角形的原理是什么?
- 常见的兼容性问题
- 为什么要初始化CSS样式
- absolute和containing block计算方式跟正常流有什么不同
- css中的visibility属性有个collapse属性值? 在不同浏览器下有什么区别
- display: none与visibility: hidden 的区别
- position跟display、overflow、float这些属性相互叠加后会怎样
- 对BFC规范(块级格式化上下文: block formatting context)的理解
- 为什么会出现浮动和什么时候需要清除浮动?清除浮动的方式
- 上下margin重合的问题
- 设置元素浮动后,该元素的display值是多少
- 移动端的布局用过媒体查询吗
- CSS优化/提高性能的方法有哪些
- 浏览器是怎么样解析CSS选择器的
- 在网页中应该使用奇数还是偶数像素的字体
- margin和padding分别适合什么场景使用
- 元素属相的百分比设定是相对于容器的高度吗
- 全屏滚动的原理是什么?用到了CSS的那些属性
- 什么是响应式设计, 响应式设计的基本原理是什么,如何兼容低版本的IE
- 诗句滚动效果
- ::before和:after中双冒号和单冒号有什么区别?解释一下这两个伪元素的作用
- 让页面里的字体变清晰,变细用CSS怎么做
- position: fixed; 在Android下无效怎么处理
- 如果需要动手些动画, 你认为最小时间间隔是多久,为什么
- li和li之间又看不见的空白间隔是什么原因引起的?有什么解决办法
- display:inline-block什么时候会显示间隙
- 有一个高度自适应的div,里面有两个div,一个高度100ox,希望另一个天马剩下的高度
- png, jpg, gif这些图片格式解释一下,分别什么时候用,有没有了解过webp
- style标签卸载body后和body前有什么区别
- CSS属性overflow属性定义溢出元素内容区的内容会如何处理
- 阐述一下CSS Sprites
ES6面试题
- let const var 比较
- 反引号(``)标识
- 函数默认参数
- 箭头函数
- 属性简写
- 方法简写
- Object.keys()方法,获取对象的所有属性名或方法名
- Object.assign()原对象的属性和方法都合并到了目标对象
- for...of循环
- import和export
- Promise对象
- 解构赋值
- set数据结构(可用于快速去重)
- Spread Operator展开运算符(...)
- 字符串新增方法
ES6数组面试题
- forEach()
- map()
- filter()
- reduce()
- some()
- every()
- all()
ES6编程题
- 使用解构,实现两个变量的值得交换
- 利用数组推到,计算出数组[1, 2, 3, 4]每一个元素的平方并组成新的数组
微信小程序开发
- 注册小程序
- 微信开发者工具
- 小程序与普通网页开发的区别
- 小程序尺寸单位rpx
- 样式导入(WeUI for)
- 选择器
- 小程序image高度自适应及裁剪问题
- 微信小程序长按识别二维码
- 给页面加背景色
- 微信小程序获取用户信息
- 代码审核和发布
- 小程序微信认证
- 小程序申请微信支付
- 小程序的目录结构及四中文件类型
- 小程序文件的作用于
- 小程序常用组件
- view
- scroll-view
- swiper
- movable-view
- cover-view
- cover-image
小程序基础
- 授权得到用户信息
- 数据绑定
- 列表渲染
- 条件渲染
- 公共模板简历
- 事件及事件绑定
- 引用
- 页面跳转
- wx.switchTab
- wx.reLaunch
- wx.redirectTo
- x.navigateTo
- wx.navigateBack
- 设置tabBar
- 页面生命周期
- 转发分享
小程序高级
- request请求后台接口
- http-promise封装
- webview
- 获取用户收货地址
- 获取地理位置
- 自定义组件
- 微信小程序支付问题
小程序项目实战
- 微信小程序本地数据缓存
- 下拉刷新和下拉加载
- 列表页向详情页跳转(动态修改title)
- 客服电话
- 星级评分组件
- 小程序插槽的使用slot
- 模糊查询
- wxs过滤
- 小程序动画
- 列表根据所引致渲染
- 小程序动态修改class
- 小程序常用框架
- 参数传值的方法
- 提高小程序的应用速度
- 微信小程序的优劣势
- 小程序的双向绑定和vue的区别
- 微信小程序给按钮添加动画
- 微信小程序的tab按钮的转化
- 为小程序引进echarts
- app打开小程序流程
- 小程序解析富文本编辑器
小程序常见bug
- 域名必须是HTTPS
- input组件placeholder字体颜色
- wx.navigateTo无法跳转到tabbar的页面
- tabbar在切换时页面数据无法刷新
- 如何去掉自定义button灰色的圆角边框
- input textarea是APP的原生组件, z-index层级最高
- 一段文字如何换行
- 设置最外成标签的margin-bottom在IOS下不生效
- 小程序中canvas的图片不支持base64格式
- 回到页面顶部
- wx.setStorageSync和wx.getStorageSync报错问题
- 如何获取微信群名称
- new Date跨平台兼容性问题
- wx.getSystemInfoSyns获取windowHeight不准确
- 图片本地资源名称,尽量使用小写命名
移动端热点问题
- px border问题
- 2X图 3X图适配
- 图片在安卓上, 有些设备模糊问题
- 固定定位布局, 键盘挡住输入框内容
- click的300ms延迟问题和点击穿透问题
- phone以及ipad下输入框默认内阴影
- 防止手机中页面放大和缩小
- px, em, rem, %, vw, vh, vm这些单位的区别
- 移动端适配 - dpr浅析
- 移动端扩展点击区域
- 上下拉动滚动条时 卡顿、慢
- 长时间按住页面出现闪退
- iOS和Android下触摸元素时出现半透明灰色遮罩
- active兼容处理 即伪类 :active失效
- webkit mask兼容处理
- pc端与移动端字体大小的问题
- transition闪屏
- 圆角bug
- 如何解决禁用表单后移动端样式不统一问题
本文来自博客园,作者:MerLin97,转载请注明原文链接:https://www.cnblogs.com/merlin97/p/13965256.html