vue常见面试题
1. vue优点
低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
2. vue父组件向子组件传递数据?
-
父组件将数据绑定在子组件上
<template> <transition name="slide"> <music-list :songs="songs" :title="title" :bg-image="bgImage"></music-list> </transition> </template>
-
子组件接受数据prop
export default {
props: {
bgImage: {
type: String,
default: ''
},
songs: {
type: Array,
default: () => []
},
title: {
type: String,
default: ''
}
},
}
3. 子组件像父组件传递事件
在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了
父组件
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
子组件
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
4. v-show和v-if指令的共同点和不同点
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
5. 如何让CSS只在当前组件中起作用
将当前组件的修改为
6. 的作用是什么?
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
7. 如何获取dom
通过refs方法
<div id="App">
<div class="aa" ref="menuItem" @click="aa($event)">aa</div>
<div @click="bb"\>bb</div>
</div>
JS
<script>
new Vue({
el: '#App',
methods: {
bb: function() {
var getMenuText = this.$refs.menuItem.innerText;
console.log(getMenuText);//aa
},
aa: function(e) {
var el = e.target;
console.log(el);//<div class="aa">aa</div>
}
}
})
</script>
8. 说出几种vue当中的指令和它的用法?
v-if:判断是否隐藏;
v-for:数据循环;
v-bind:class:绑定一个属性;
v-model:实现双向绑定
9. vue-loader是什么?使用它的用途有哪些?
vue文件的一个加载器。
用途:js可以写es6、style样式可以scss或less、template可以加jade等
根据官网的定义,vue-loader 是 webpack 的一个 loader,用于处理 .vue 文件。
10. 为什么使用key
当有相同标签名的元素切换时,需要通过key 特性设置唯一的值来标记以让Vue 区分它们,否则Vue 为了效率只会替换相同标签内部的内容。
11. axios及安装
1.axios是什么?
请求后台资源的模块
2.axios安装?
根目录运行
npm install axios -S
在使用的地方
import axios from ‘axios’
12. axios解决跨域
首先在build/webpack.dev.conf.js设置代理
var express \= require('express')
var axios \= require('axios')
var app \= express()
var apiRoutes \= express.Router()
app.use('/api', apiRoutes)before(apiRoutes) {
apiRoutes.get('/api/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg' // 原api
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
}
在页面中使用
export function getDiscList() {
const url = '/api/getDiscList'
const data = Object.assign({}, commonParams, {
platform: 'yqq',
hostUin: 0,
sin: 0,
ein: 29,
sortId: 5,
needNewCode: 0,
categoryId: 10000000,
rnd: Math.random(),
format: 'json'
})
return axios.get(url, {
params: data
}).then((res) => {
return Promise.resolve(res.data)
})}
13. v-modal的使用
用v-model指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model在内部使用不同的属性为不同的输入元素并抛出不同的事件:
l text 和 textarea 元素使用value属性和input事件;
l checkbox 和 radio 使用checked属性和change事件;
l select 字段将value作为 prop 并将change作为事件。
14. scss的安装以及使用
1、开始在vue项目中使用sass,在命令行输入一下命令进行安装(使用git命令行要用shift+insert 进行粘贴否则粘贴不上)
cnpm install node-sass --save-dev //安装node-sass
cnpm install sass-loader --save-dev //安装sass-loader
cnpm install style-loader --save-dev //安装style-loader 有些人安装的是 vue-style-loader 其实是一样的!
2、这个时候你打开build文件夹下面的webpack.base.config.js
把里面的module改成这样的
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'),
resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
},
{ //从这一段上面是默认的!不用改!下面是没有的需要你手动添加,相当于是编译识别sass!
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
}
3、在需要用到sass的地方添加lang=scss
<style lang="scss" scoped="" type="text/css"> //你的sass语言 $primary-color: #333;
body {
color: $primary-color; //编译后就成了 color:#333;类似于js的变量!
}
</style>
15. 请说出vue.cli项目中src目录每个文件夹和文件的用法?
assets文件夹是放静态资源;
components是放组件;
router是定义路由相关的配置;view视图;
app.vue是一个应用主组件;
main.js是入口文件
16. 分别简述computed和watch的使用场景
一. methods和(watch、computed)的 区别
1.watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情:当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动。
2.对methods:methods里面是用来定义函数的,很显然,它需要手动调用才能执行。而不像watch和computed那样,“自动执行”预先定义的函数
二. methods和computed的 相比 computed的好处
import Vue from 'vue'
new Vue({
el: '#root',
template: `
<div>
<p>Name: {{name}}</p>
<p>Name: {{getName()}}</p>
<p>Number: {{number}}</p>
<p><input type="text" v-model="number"/></p>
<p>FirsName: <input type="text" v-model="firstName"/></p>
<p>LaseName: <input type="text" v-model="lastName"/></p>
</div>
data: {
firstName: 'Jokcy',
lastName: 'Lou',
number: 0
},
computed: {
name () {
console.log('new name')
return `${this.firstName} ${this.lastName}`
}
},
methods: {
getName () {
console.log('getName invoked')
return `${this.firstName} ${this.lastName}`
}
}
})
当我们改变 number 时,整个应用会重新渲染,vue 会被数据重新渲染到 dom 中。这时,如果我们使用 getName 方法,随着渲染,方法也会被调用,而 computed 不会重新进行计算,从而性能开销比较小。当新的值需要大量计算才能得到,缓存的意义就非常大。
如果 computed 所依赖的数据发生改变时,计算属性才会重新计算,并进行缓存;当改变其他数据时,computed 属性 并不会重新计算,从而提升性能。
当我们拿到的值需要进行一定处理使用时,就可以使用 computed。
三. watc和computed的 区别
1.watch 监听某个数据的变化(监听完调用什么函数) 一个数据影响多个数据 (比如:浏览器自适应、监控路由对象、监控自身属性变化)
computed 计算后返回新 一个数据受多个数据影响(比如:计算总价格、过滤某些数据)
2.就算在data中没有直接声明出要计算的变量,也可以直接在computed中写入。如果在data中没有相应的属性的话,是不能watch的,这点和computed不一样。
3.computed是用来处理你使用watch和methods的时候无法处理(比如有缓存的时候监听不了数据变化),或者是处理起来并不太恰当的情况的,利用computed处理methods存在的重复计算情况
watch: {
firstName(val) { this.fullName = val + this.lastName }}
computed: {
fullName() { this.firstName + this.lastName; }}
17. v-on可以监听多个方法吗
v-on可以监听多个方法,例如:
<input type=“text” :value=“name” @input=“onInput” @focus=“onFocus” @blur=“onBlur” />
但是同一种事件类型的方法,vue-cli工程会报错,例如:
<input type=“text” :value=“name” @input=“onInput” @focus=“onFocus” @blur=“onBlur” />
18. $nextTick的使用
一、为什么使用$nextTick
因为Vue中DOM更新是异步的
$nextTick是DOM更新完成后执行的
二、在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中?
在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted()钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
三、$nextTick的其他应用
在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
四 $nextTick的原理
作用
Vue.nextTick用于延迟执行一段代码,它接受2个参数(回调函数和执行回调函数的上下文环境),如果没有提供回调函数,那么将返回promise对象。
源码
/**
\* Defer a task to execute it asynchronously.
*/
export const nextTick = (function () {
const callbacks = []
let pending = false
let timerFunc
function nextTickHandler () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
// the nextTick behavior leverages the microtask queue, which can be accessed
// via either native Promise.then or MutationObserver.
// MutationObserver has wider support, however it is seriously bugged in
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
// completely stops working after triggering a few times... so, if native
// Promise is available, we will use it:
/* istanbul ignore if */
if (typeof Promise !== 'undefined' && isNative(Promise)) {
var p = Promise.resolve()
var logError = err => { console.error(err) }
timerFunc = () => {
p.then(nextTickHandler).catch(logError)
// in problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) setTimeout(noop)
}
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// use MutationObserver where native Promise is not available,
// e.g. PhantomJS, iOS7, Android 4.4
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
} else {
// fallback to setTimeout
/* istanbul ignore next */
timerFunc = () => {
setTimeout(nextTickHandler, 0)
}
}
return function queueNextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
timerFunc()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
_resolve = resolve
})
}
}})()
首先,先了解nextTick中定义的三个重要变量。
l callbacks
用来存储所有需要执行的回调函数
l pending
用来标志是否正在执行回调函数
l timerFunc
用来触发执行回调函数
接下来,了解nextTickHandler()函数。
function nextTickHandler () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
这个函数用来执行callbacks里存储的所有回调函数。
接下来是将触发方式赋值给timerFunc。
先判断是否原生支持promise,如果支持,则利用promise来触发执行回调函数;
否则,如果支持MutationObserver,则实例化一个观察者对象,观察文本节点发生变化时,触发执行所有回调函数。
如果都不支持,则利用setTimeout设置延时为0。
最后是queueNextTick函数。因为nextTick是一个即时函数,所以queueNextTick函数是返回的函数,接受用户传入的参数,用来往callbacks里存入回调函数。
上图是整个执行流程,关键在于timeFunc(),该函数起到延迟执行的作用。
从上面的介绍,可以得知timeFunc()一共有三种实现方式。
Promise
MutationObserver
setTimeout
其中Promise和setTimeout很好理解,是一个异步任务,会在同步任务以及更新DOM的异步任务之后回调具体函数。
19. vue组件中data为什么必须是一个函数
为什么组件中data必须是一个函数了而不是对象, 我们首先来看一下第一个声明式渲染的demo中data我们只在当前页面的挂载的div#app这个点上使用,但是对于组件有一个很明显的特性是在于它是可以被复用的,好了知道了这一点我们以一个全局注册一个组件来分析
我们先假设将data作为一个对象:
我们前面说组件是可以被复用的,那么注册了一个组件本质上就是创建了一个组件构造器的引用,而真正当我们使用组件的时候才会去将组件实例化,
// 创建一个组件
var Component= function() {}
Component.prototype.data = {
a: 1,
b: 2}
// 使用组件
var component1 = new Component()
var component2 = new Component()
component1.data.b = 3
component2.data.b // 3
我们可以发现当我们使用组件的时候,虽然data是在构造器的原型链上被创建的,但是实例化的component1和component2确是共享同样的data对象,当你修改一个属性的时候,data也会发生改变,这明显不是我们想要的效果。
var Component= function() {}
Component.prototype.data = function() {
return {
a: 1,
b: 2
}}
// 使用组件
var component1 = new Component()
var component2 = new Component()
component1.data.b = 3
component2.data.b // 2
当我们的data是一个函数的时候,每一个实例的data属性都是独立的,不会相互影响了。你现在知道为什么vue组件的data必须是函数了吧。这都是因为js本身的特性带来的,跟vue本身设计无关。
20. vue事件对象的使用
<button data-aid="123" @click="getInfo($event)">通过事件对象获取自定义属性</button>
getInfo(event){
//获取自定义data-id
console.log(event.target.dataset.id)
//阻止事件冒泡
event.stopPropagation();
//阻止默认
event.preventDefault()}