Key的比较方法
•比较同一层级,不跨级比较
•tag 不相同,则直接删掉重建,不再深度比较
•tag 和key ,两者都相同,则认为是相同节点,不再深度比较
为何在v-for 中使用key
•必须用key ,且不能是 index 和random
•diff 算法中通过 tag 和key 来判断,是否是 sameNode
•減少渲染次数,提升渲染性能
computed 有何特点
•有缓存,data 不变不会重新计算
•提升性能
ajax 请求应该放在哪个生命周期
•mounted
•JS是单线程的,ajax 异步获取数据
•放在mounted 之前没有用,只会让逻辑更加混乱
如何自己实现 v-model
<template>
<input
type="text"
:value="text1"
@input="$emit ('change', $event.target.value)"/
>
</template>
<script>
export default {
model: {
prop:'text1',
event:'change'
},
props:{
text1:String
}
}
</script>
Vue.mixin 的使用场景和原理
在日常开发中,我们经常会遇到在不同组件中经常用到一些相同或者相似的代码,这些代码的功能相对独立,可以通过vue 的 mixin 功能抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用 mergeOptions 方法进行合并,采用策略模式针对不同的属性进行合并。当组件和混入对象含有相同名选项时,这些选项将以恰当的方式进行“合并”。
缺点:命名冲突、数据来源不清晰
使用方法:
//定义方法 文件路径:mixins/mymixin.js
let mymixin={
methods:{
handleBtn(){
alert('封装的内容已经触发!')
}
}
}
export default mymixin
//main.js文件
import myMixin from "./mixins/mymixin.js"
// 全局混入:我们把封装好的这个组件在main.js中全局注册,方便在任何地方使用
Vue.mixin(mymixin)
//局部混入,只在当前组件可以使用
<template>
<button @click="handleBtn">点我触发</button>
</template>
<script>
import mymixin from '@/mymixin.js'
export default {
mixins:[mymixin]
}
</script>
vuex和mixin的区别
vuex是所有组件公用数据,响应式。组件a对vuex的state的x修改,组件b使用了vuex的state的x会跟着变化。
mixin中的data大概可以理解为复制粘贴代码到引用mixin的组件,即组件a和组件b中的data中的x是相互独立的,不会组件a中的x改了组件b中的x跟着改。
何时需要使用keep-alive?
•缓存组件,不需要重复渲染,如多个静态 tab 的切换
•优化性能
Vue 常用性能优化方式
- 代码优化
• 合理使用 v-show 和v-if
• 合理使用 computed
• v-for 时加 key ,以及避免和v-if 同时使用
• 自定义事件、DOM 事件及时销毁
• 合理使用路由懒加载,异步组件
• 尽可能拆分组件,提高复用性、维护性
• 合理使用 keep-alive,data层级不要太深
• 数据持久化存储的使用尽量用防抖、节流优化
• 使用vue-loader 在开发环境做模板编译(预编译) - 加载优化
• 图片懒加载,内容懒加载
• 组件按需加载 - 打包优化
• CDN形式加载第三方模块
• 抽离公共文件
什么是SPA应用,SPA页面和传统页面有什么区别?
单页面应用,仅在该Web页面初始化时加载相应的HTML、JavaScript、CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转。
Vue的组件data为什么必须是一个函数?
一个组件被复用多次的话,也就会创建多个实例,本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例,所以为了保证组件不同的实例之间data不冲突,data必须是一个函数
为了防止两个组件的数据产生污染。 如果都是对象的话,会在合并的时候,指向同一个地址。 而如果是函数的时候,合并的时候调用,会产生两个空间。
什么是vuex,vuerouter,如何避免vuex中的函数造成全局污染
vuex 为状态管理,它集中存储管理应用的所有组件的状态,可以理解成一个全局仓库。
VueRouter是路由(spa)单页面应用的方式
避免全局变量污染:1.唯一变量:将变量都挂载到同一个命名空间下 2.使用闭包
为什么通过vuex的mutation修改state中的参数就不会报错,而直接更改state中的参数就会报错(使用严格模式才报错)
原因:如果通过外部直接修改state,则没有执行 commit 函数,通过mutation修改state执行了commit函数,不执行commit函数_withCommitting不为true,则报出异常。
1.使用vuex修改state时,有两种方式:
(1)可以直接使用this.$store.变量=xxx;
(2)this. $store.dispatch、this. $store.commit;
2.异同点:
(1)共同点:能够修改state里的变量,并且是响应式的(能触发视图更新)
(2)不同点:若将vue创建store的时候传入strict true,开启严格模式,那么任何修改state的操作,只要不经过mutation函数就会报错
vue中使用插件的步骤?
安装:npm install xxx
引入: import ... from ...;
使用:Vue.use(xxx)
vue中引入组件有几种方式?简述步骤
两种:采用 ES6 的 import ... from ... 语法或 CommonJS 的 require() 方法引入组件
//方法一
import Calendar from "./calendar";
export default {
name: "SymptomMain",
components: {
Calendar
},
}
//方法二
export default {
//1.直接在components中写入子组件
components: {
Calendar:require('./calendar.vue').default
},
}
vue-router 有哪几种导航钩子
1.全局导航钩子:作用:跳转前进行判断拦截。
2.组件内的钩子;
3.单独路由独享组件
*全局导航钩子
router.beforeEach(to,from,next);
router.beforeResolve(to,from,next);
router.afterEach(to,from,next);
*组件内钩子
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
*单独路由独享组件
beforeEnter
NextTick是做什么的?
$nextTick
是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick
,则可以在回调中获取更新后的DOM。
使用场景:需要在视图更新之后,基于新的视图进行操作。比如需要在生命周期的created()函数中进行一些DOM操作,要把相关代码放在Vue.nextTick()的回调函数中。又或者在数据变化后要执行某个动作,而这个动作需要使用随数据变化而改变的DOM结构的时候。
原理:就是 $nextTick
将回调函数放到微任务或者宏任务当中以延迟它地执行顺序。函数中主要有3个参数:
•callback:我们要执行的操作,可以放在这个函数当中,我们每执行一次$nextTick就会把回调函数放到一个异步队列当中;
•pending:标识,用以判断在某个事件循环中是否为第一次加入,第一次加入的时候才触发异步执行的队列挂载
•timerFunc:用来触发执行回调函数,也就是Promise.then或MutationObserver或setImmediate 或setTimeout的过程
vue中key的作用
key的作用主要是为了高效的更新虚拟DOM
** 如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
** 如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
keep-alive的了解
keep-alive是vue内置的一个组件,可以在组件切换时保留被包裹组件的状态,使其不被销毁,防止重复渲染dom
$router
和$route
的区别
$router
为VueRouter实例,想要导航到不同的url,则使用 $router.push
方法;
$route
为当前router跳转对象里面可以获取name、path、query、params等。
vuex有哪几种状态和属性
有五种,分别是 State、 Getter、Mutation 、Action、 Module (就是mapAction等)
vuex的流程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation。mutation会修改state中对应的值。
最后通过getter把对应值跑出去,在页面的计算属性中,通过mapGetter来动态获取state中的值
computed和watch的区别
1、computed是计算属性;watch是监听,监听data中的数据变化。
2、computed支持缓存,当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值;watch不支持缓存,当对应属性发生变化的时候,响应执行。
3、computed不支持异步,有异步操作时无法监听数据变化;watch支持异步操作。
4、computed第一次加载时就监听;watch默认第一次加载时不监听。
immediate 组件创建时刻执行与否
immediate: true,第一次加载时监听(默认为false)
deep 深度监听 不推荐使用(非常的消耗性能)
监听的属性是对象的话 不开启deep 对象子属性变化不会触发watch
开启了deep 对象内部所有子属性变化 都会触发watch
5、computed中的函数必须调用return;watch不是。
6、使用场景:
computed:一个属性受到多个属性影响,如:购物车商品结算。
watch:一个数据影响多条数据,如:搜索数据。
数据变化响应,执行异步操作,或高性能消耗的操作,watch为最佳选择。
vue修饰符
1.事件修饰符
.stop .prevent .once(点击事件只会触发一次) .native(使用时将被当成原生HTML标签看待)
- 按键修饰符
.enter,.tab,.delete,.esc,.up,.down,.space
- 表单修饰符
.lazy .trim .number
axios封装
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 100000
})
service.interceptors.request.use(config => {
const token = window.sessionStorage.getItem('RToken')
console.log(1)
if (token) { // 携带token
config.headers.Authorization = `Bearer ${token}`
}
return config
}, error => {
console.log(error)
return Promise.reject(error)
})
service.interceptors.response.use(response => {
return response.data
}, error => {
console.log('err' + error) // for debug
return Promise.reject(error)
})
export default service
proxy配置
module.exports = {
publicPath: "/",
devServer: {
proxy: {
"/api": {
// 代理名称 凡是使用/api开头的地址都是用此代理
target: "http://1.2.3.4:5000/", // 需要代理访问的api地址
changeOrigin: true, // 允许跨域请求
pathRewrite: {
// 重写路径,替换请求地址中的指定路径
"^/api": "/", // 将请求地址中的/api替换为空,也就是请求地址中不会包含/api/
},
},
},
},
};
$set的用法
this.$set(原数组,索引值,想要赋的值)
使用场景:
1.利用索引值直接修改一个数组中的值时
2.直接修改数组的length
3.对象新增的属性值不具有响应式,如果要修改这个值让其具有响应式时使用$set
修改一个属性的值:this.$set(this.userInfo,'age',18)
;
修改对象多个属性的值:
this.userInfo= Object.assign({}, this.userInfo, {
age: 27,
name: 'Joe'
})
ps:使用$set实现上移下移
<el-button size="mini" @click="moveUp(value[index],index)">上移</el-button>
<el-button size="mini" @click="moveDown(value[index],index)">下移</el-button>
moveUp(item, index) {
if (this.value.length > 1 && index !== 0) {
var temp = this.value[index - 1];
this.$set(this.value, index - 1, this.value[index]);
this.$set(this.value, index, temp);
}
},
moveDown(item, index) {
if (this.value.length > 1 && index != this.value.length - 1) {
var temp = this.value[index + 1];
this.$set(this.value, index + 1, this.value[index]);
this.$set(this.value, index, temp);
}
},
vuex 数据持久化 PersistedState
安装:npm i vuex-persistedstate --save
引入:import createPersistedState from 'vuex-persistedstate';
plugins: [
createPersistedState({
key: 'vuex', // 存储的变量名
storage: window.localStorage// 也可以是sessionstorage
})
]
路由懒加载的方法
{
path;'/home',
name:'Home',
component: ()=>import('@/pages/Home'),
}