目录
1. Vue常见的指令有哪些,有什么用
指令 |
作用 |
备注 |
v-cloak |
防止页面闪烁 |
在vue加载之前v-cloak是存在,vue加载结束之后v-cloak就隐藏了,利用这个特性可以实现:界面防止闪烁 |
v-text |
会替换掉元素里的内容 |
区别: v-html会解析HTML代码和样式(富文本) v-text直接展示原始内容 |
v-html |
可以渲染html界面 |
|
v-bind |
属性绑定 |
1. 界面元素属性值的绑定 2. 括号里不加引号的都是我们data里的数据读取 3. 如果想使用字符串需要加上引号 4. 里面可以写表达式 5. 里面也可以调用定义好的方法,拿到的是方法的返回值 6. 简写 : |
v-on |
事件绑定 |
简写@ |
v-model |
数据双向绑定 |
1. 作用:数据双向绑定 2. 注意:绑定的是表单控件 3. 双向数据绑定: 数据变化后更新视图;视图变化后更新数据。Model层里的数据和View层上的数据只要有一方变化,另一方随之改变。 4. 原理: 后面有详细说明 |
v-for :key |
遍历 |
1. 遍历数组,参数(item,index) in list 2. 遍历对象,参数(value,key,index) in list 3. 遍历数字,num in 10 (1~10) 4. key在使用v-for的时候都需要去设置key 4-1. 让界面元素和数组里的每个记录进行绑定 4-2. key只能是字符串或者数字 4-3. key必须是唯一的 4-4. “就地复用” 策略 4-5. key值的作用---提高重拍效率 4-6. key值的计算方法---diff算法 |
v-if v-else |
通过元素的删除和添加控制元素的显示和隐藏 |
1. 区别 1-1. v-if删除dom元素 1-2. v-show设置display:none 2. 应用场景 2-1. v-if只修改一次的时候可以使用v-if 2-2. v-show频繁切换的时候可以使用v-show |
v-show |
通过display属性,控制元素的显示和隐藏 |
2. 双向数据绑定的原理
vue2双向数据绑定原理
双向数据绑定v-model的原理:采用“数据劫持”结合“发布者-订阅者”模式的方式,通过“Object.defineProperty()”方法来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变。
Object.defineProperty()方法有三个参数:
obj:属性的对象。
prop:要定义或修改的属性。
descriptor:一个对象,包括get和set方法
缺点:
根据官方文档,双向数据绑定失效总共有三种情况:
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
- 对象中的属性增加或删除时
vue3双向数据绑定原理
通过Proxy(代理)的方式实现,拦截对data任意属性的操作, 包括属性值的读写、添加、删除等;通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作。
区别
Object.defineProperty 是 ES5 的方法,Proxy 是 ES6 的方法
Object.defineProperty 不能监听到数组下标变化和对象新增属性,Proxy可以
Object.defineProperty是劫持对象属性,Proxy是代理整个对象
Object.defineProperty局限性大,只能针对单属性监听,所以在一开始就要全部递归监听。Proxy对象嵌套属性运行时递归,用到才代理,也不需要维护特别多的依赖关系,性能提升很大,且首次渲染更快
Object.defineProperty 会污染源对象,修改时是修改源对象。Proxy是对原对象进行代理并返回一个新的代理对象,修改的是代理对象
3. 路由的跳转和传参有哪几种方式
声明式
<router-link to="{path:'/son1' ,query:{ id:'10' }}" >跳转</router-link>
<router-link to="{name:'son1' ,params:{ id:'10' }}" >跳转</router-link>
函数式
this.$router.push({
name: "namelogin",
params: {
userid: 999,
name: "wangwu"
}
})
this.$router.push({
path: "namelogin",
query: {
userid: 999,
name: "wangwu"
}
})
其他
this.$router.replace()
replace 先移除,再放入,没有历史数据
push 相当于覆盖,有历史数据
go(数字) 返回上个页面
前进为正数,后退为负数,0就是本页面
back == go(-1) 返回上一页面
4. 组件间的通讯方式有哪些
通讯方式 | 使用方法 | 备注 |
---|---|---|
父传子 | 子组件:设置props属性就可以接受父组件传值 | 注意: data和props的区别 data是组件私有的,props是父组件传过来的 data是可以修改的,props是只读的 |
子传父 | 父组件:在父组件中给引用的子组件注册一个事件(这个事件的名字是自定义的) 子组件:子组件可以触发这个事件$emit('事件名字') |
1. $emit方法第二个参数可以定义子组件给父组件传递的内容 2. 在父组件中拿到这内容 2.1 父组件这个方法没有自定参数,在父组件的方法直接加这个参数就可以拿到 2.2 父组件有自定义参数,可以传入$event也可以拿到子组件传递的数据。通过$event只能传递第一个参数。 |
vuex | 将数据放在states中,进行统一管理 | 下面对vuex有详细解释 |
缓存 | localStorage/sessionStorage | 保存在本地,需要注意时效性 |
ref | 给dom节点加上ref属性 | 1. 获取dom节点 1.1 给dom节点记上ref属性,可以理解为给dom节点起了个名字。 1.2 加上ref之后,在$refs属性中多了这个元素的引用。 1.3 通过vue实例的$refs属性拿到这个dom元素。 2. 获取组件 2.1 给组件记上ref属性,可以理解为给组件起了个名字。 2.2 加上ref之后,在$refs属性中多了这个组件的引用。 2.3 通过vue实例的$refs属性拿到这个组件的引用,之后可以通过这个引用调用子组件的方法,或者获取子组件的数据。 |
事件总线 | |
事件总线可以作为组件沟通的桥梁,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件 但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。 |
5. 谈一谈对路由守卫的理解
路由守卫
1. vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。简单的说,导航守卫就是路由跳转过程中的一些钩子函数。
2. 全局守卫:是指路由实例上直接操作的钩子函数,特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数
- beforeEach(to,from, next)路由进入之前
- beforeResolve(to,from, next)路由解析之前 这个几乎不用
- afterEach(to,from)路由进入之后
3. 路由独享守卫:是指在单个路由配置的时候也可以设置的钩子函数
- beforeEnter(to,from,next)
4. 组件守卫:是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。
- beforeRouteEnter(to,from, next)
- beforeRouteUpdate(to,from, next)
- beforeRouteLeave(to,from, next)
5. 记住参数或查询的改变并不会触发进入/离开的导航守卫。可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
6. 分为 全局守卫 路由独享守卫 和 组件守卫
全局守卫
1. 三个参数
to 跳转后的页面
from 跳转前的页面
next 是函数
直接调用 next() 允许跳转
next(false) 不允许跳转
next('/index') 代表要跳转到首页
2. 注意
确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
3. 示例
router.beforeEach((to, from, next) => {
console.log(to):
console.log(from)
console.log(next)
})
router.beforeEach( ( to , from , next ) => {
// 在跳转之前就可以增加逻辑判断了,根据不同的状态判断能否跳转到指定的页面
// 比如搜索页面需要登录后才可以进入
if(to.meta.isLogin){
// 判断是否登录 写判断是否登录
next("/")
}else {
// 不需要登录
next()
}
// next(false)
// 判断 那些页面是需要登录的 那些页面是不需要登录的
}
路由独享的守卫
可以在路由配置上直接定义 beforeEnter
守卫:这些守卫与全局前置守卫的方法参数是一样的。
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
6. 谈一谈对Vuex的理解
VUEX
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储,管理应用中所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
作用
1、进行统一的状态管理,解决不同组件共享数据的问题。
2、不同视图需要变更同一状态的问题。
3、使用vuex之后,状态变化更加清晰。
-
核心概念
state getter mutation action module
1、state 存放全局初始化变量
1.state是一个单一状态树,是vuex中为一个的数据源,我们的数据都是放在state中的。
2. 组件中去取state的值,通过this.$store.state。或者可以通过计算属性取得,mapState辅助函数,可以简化操作。
import {mapState} from "vuex";
computed: {
// 可以写一些其他的计算属性
...mapState({
// title: state => state.title
// title: "title"
title: state => {
return state.title;
}
})
}
2、getter 对象状态进行加工函数
1. 对state中的数据进行加工(派生)
2. 取getters中的值,通过this.$store.getters,或者通过计算属性获取,getters也有辅助函数mapGetters, 用法和mapState一致。
import { mapGetters} from "vuex";
computed: {
// 可以写一些其他的计算属性
... mapGetters ({
title: "title"
})
}
3、mutation 修改state的状态
1. 修改state中的值,我们state每次变化,都应该由mutation去修改,方便追踪数据的流转
2.定义mutation
const store = new Vuex.Store({
// ....
mutations: {
increment(state, count) {
state.count = count
},
}
})
3. 调用mutation
- this.$store.commit('mutation类型(函数名)',"参数,参数一般是对象形式")
- this.$store.commit({type:'mutation类型(函数名)'},...其他参数)
4. 注意事项
- 要遵循vue相应式变化的规则,简单说就是对于对象的赋值,要用新对象替换老对象。
- mutation的type或者说是函数名可以用常量维护。
- mutation函数必须是同步的。
4、action 执行异步操作,不能修改
1. action类似于mutation,不同的是
action可以包含异步操作
action不能直接修改state,如果想修改state的话,需要触发mutation
2. 定义
actions: {
// 通过context(上下文环境)可以触发mutation,触发action,获取state、getter等操作
// 第二个参数就是我们传递过来的参数
changeTitle(context,payload) {
setTimeout(() => {
context.commit(CHANGE_TITLE, payload)
}, 1000);
}
}
3. 触发action
- this.$store.dispatch('action名字','参数')
- this.$store.dispatch({type:'action类型(函数名)'},...其他参数)
5、module 模块
1. 由于使用单一的状态树,项目中的状态会集中在一起,导致难以维护,这个时候可以通过module对store进行拆分。
2. 使用module之后,每个模块都有自己的state、mutation等内容,方便维护
3. 定义
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
4. 命名空间
- 默认state就是有命名空间
- 如果想给mutation和action也加上命名空间的话,这里设置模块的namespaced:true
const moduleA = {
namespaced:true,
state: { ... },
mutations: {
changeName(){}
},
actions: { ... },
getters: { ... }
}
// this.$store.commit('a/changeName')
5. 命名空间之后使用辅助函数createNamespacedHelpers
解决vuex刷新状态重置问题
1、存入缓存
2、在接口请求之后确定状态
其他
单向数据流转
状态:驱动应用的数据源
视图:以声明方式将状态映射到视图
操作:响应在视图上用户输入导致的状态变化
7. 谈一谈对混入的理解
混入
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
选项合并
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
// 定义一个混入对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混入对象的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
全局混入
混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
注意
谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。
8. 谈一谈对插槽的理解
插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。
插槽的使用
如果子组件没有使用插槽,父组件如果需要往子组件中填充模板或者html, 是没法做到的
1、具名插槽
具名插槽其实就是给插槽娶个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
父组件填充内容时,是可以根据这个名字把内容填充到对应插槽中
子组件:在子组件的slot标签中加上name属性
父组件:父组件通过 v-slot:name值 的方式指定到对应的插槽中
2、默认插槽
默认插槽就是指没有名字的插槽,子组件未定义的名字的插槽,父级将会把 未指定插槽的填充的内容填充到默认插槽中。
子组件:在子组件中放一个占位符<slot></slot>标签
父组件:直接给子组件元素填充内容
注意
1. 父级的填充内容如果指定到子组件的没有对应名字插槽,那么该内容不会被填充到默认插槽中。
2. 如果子组件没有默认插槽,而父级的填充内容指定到默认插槽中,那么该内容就“不会”填充到子组件的任何一个插槽中。
3. 如果子组件有多个默认插槽,而父组件所有指定到默认插槽的填充内容,将“会” “全都”填充到子组件的每个默认插槽中。
9. 什么是跨域,如何解决
同源策略CORS
浏览器的一个安全协议(不限制服务),协议主机端口要保持一致,只要有一个不一致就是跨域请求
解决跨域
1. 后台直接不做限制,放开所有请求。优点:方便;缺点:不安全。
2. JSONP(和JSON没有太大关系)利用了script标签不受同源策略,需要后端配合(现在不咋用了)
3. 配置代理(现在90%以上都在用)
4. 在vue.config.js中进行配置代理(可以配置多个)
10. 谈一谈封装请求的心得
- 1. 封装请求可以对请求进行统一化的管理,易于维护,对开发人员来说十分简便,此外,可以对请求开始前及过程中进行预处理,提高了请求的效率。
- 2. axios封装的好处:统一处理,提高效率,便于维护。不用再挂载在Vue实例的原型上,降低了耦合度,两者互不相干了,其中的任何一个出现问题,另一个都能正常运作。
11. watch和computed的共同点和不同点
共同点
都能监听属性的改变触发函数程序
不同点
- watch中的函数是不需要调用的
- computed内部的函数调用的时候不需要加()
- watch: 属性监听 监听属性的变化
- computed: 计算属性 通过属性计算而得来的属性
- watch需要在数据变化时执行异步或开销较大的操作时使用
- computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用
- computed中的函数必须用return返回最终的结果,当computed中的函数所依赖的属性如果没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取
从作用机制上:
- methods,watch 和 computed 都是以函数为基础的,但各自却都不同
- watch 和 computed 都是以 Vue 的依赖追踪机制为基础的,当某一个数据发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动
- 对 methods:methods 里面是用来定义函数的,它需要手动调用才能执行。而不像 watch 和 computed 那样,“自动执行”预先定义的函数,相比于 watch / computed,methods 不处理数据逻辑关系,只提供可调用的函数
从性质上:
- methods 里面定义的是函数,仍然需要去调用它。
- computed 是计算属性,事实上和 data 对象里的数据属性是同一类的(使用上)。
- watch:类似于监听机制+事件机制
watch 和 computed 区别
- 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
- 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
- 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return
- watch擅长处理的场景:一个数据影响多个数据 -------搜索框。
- computed擅长处理的场景:一个数据受多个数据影响 -- 使用场景:当一个值受多个属性影响的时候--------购物车商品结算
watch: {
value:{
handler:function(o,n){},
immediate: true
}
},
immediate设为true 监听方法会在创建的时候 执行handler里的方法