面试题VUE篇
温馨提示:这篇文章已超过383天没有更新,请注意相关的内容是否还可用!
文章目录
- Vue 的核心是什么/请简述你对 vue 的理解
- 请简述 vue 的单向数据流
- 槽口请简述
- Vue 常用的修饰符有哪些
- 1. 普通修饰符
- 2. 事件修饰符
- 3. 键盘修饰符
- 4. 系统修饰符
- v-text 与{{}}与 v-html 区别
- v-on 可以绑定多个方法吗
- Vue 循环的 key 作用
- 什么是计算属性
- Vue 单页面的优缺点
- Vuex 是什么?怎么使用?在那种场景下使用
- 使用
- 使用场景
- Vue 中路由跳转方式(声明式/编程式)
- Vue 中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
- Vue 路由传参的两种方式,params 和 query方式与区别
- vue 跨域的解决方式
- Vue 的生命周期
- Vue 路由的实现
- 路由守卫
- Route 与 router 区别
- Vue 路由模式 hash 和 history,简单讲一下
- Vue 数据绑定的几种方式
- Vue 注册一个全局组件
- 常用库的常用组件以及属性
- Vue-cli 中如何自定义指令
- Vue 中指令有哪些
- v-if和v-show的区别
- 对 vue 中 keep-alive 的理解
- 如何让组件中的 css 在当前组件生效
- Mvvm 与 mvc 的区别
- Vue 组件中的 data 为什么是函数
- Vue 双向绑定的原理
- 什么是虚拟dom?
- 虚拟DOM在vue框架中是怎么工作的
- 介绍一下diff算法
- vue中涉及了哪些设计模式
- 如果一个组件在多个项目中使用怎么办
- Vue 首屏加载慢的原因,怎么解决的?
- 白屏时间怎么检测,怎么解决白屏问题?
- v-for 与 v-if 优先级
- vue3是如何变得更快的?
- a. Diff 方法优化
- b. 新增的静态标记(PatchFlag)
- c. 事件侦听器缓存
- Vue 如何定义一个过滤器
Vue 的核心是什么/请简述你对 vue 的理解
- Vue.js的核心是一个用于构建用户界面的渐进式MVVM框架。
- 它主要专注于视图层,提供了一套简洁的API和高效的数据绑定机制,使开发者能够更容易地构建交互式的单页面应用(SPA)和动态用户界面。
- “渐进式” 指的是你可以逐步采用Vue.js,根据你项目的需要引入其功能,而不必强制性地将整个框架应用到整个项目。
- MVVM:Model(模型, 代表应用程序的数据和业务逻辑)、View(视图, 代表用户界面)和ViewModel(视图模型,负责处理视图和模型之间的通信。)
- MVVM模式的一个关键特点是数据绑定,这使得视图和模型之间的同步变得自动化。
请简述 vue 的单向数据流
- Vue.js的单向数据流是指数据在应用中的流动方向是单一的,从父组件到子组件。父组件通过将数据作为props传递给子组件,子组件可以通过props来接收这些数据。
- 父向子(单向数据流):
//父组件 const message = ref("hi!son") //子组件 声明式: let {placeholder}=defineProps(['placeholder']) 选项式: export default{ props:{ messagefromDad:String } }- 子向父(通过事件)
//son 声明式(setup语法糖写法) const instance = getCurrentInstance(); onMounted(()=>{ instance.emit('msg',"hello!dad!") }) //dad //监听msg自定义事件search儿子传来的东西:{{ msgfromson }}let msgfromson=ref('...') const handleMsg = (e)=>{ console.log("传过来的语句是:",e); msgfromson=e }this.$emit 是 Vue.js 中用于触发自定义事件的方法
this.$emit('eventName', payload);payload(载荷) 是可选的参数,用于传递额外的数据给父组件。
槽口请简述
子组件的插槽是为了留给父组件,允许父组件为不同插槽位置分配不同的内容。
子:
父:
Header Content
Footer Content
Vue 常用的修饰符有哪些
修饰符是一些附加在指令后面的特殊关键字,用于修改指令的行为。
1. 普通修饰符
- .stop: 阻止事件冒泡。
- .prevent: 阻止默认行为。
- .capture: 使用事件捕获模式。
- .self: 只在事件是从触发事件的元素自身触发时触发。不会触发子孙冒泡的事件。
- .lazy:将会在 “change” 事件而不是 “input” 事件时更新数据,从而减少更新的频率,提高性能。
2. 事件修饰符
- .once: 只触发一次。事件处理函数会在第一次触发后被自动解绑
- .passive: 指示浏览器不要等待 preventDefault 的调用,用于改善移动设备上的滚动性能【没看懂】
3. 键盘修饰符
使用:
- .enter: 监听 Enter 键。
- .tab: 监听 Tab 键。
- .delete 或 .backspace: 监听删除/退格键。
- .esc: 监听 Esc 键。
- .space: 监听空格键。
- .up: 监听上箭头键。
4. 系统修饰符
- .ctrl: 用于监听 Ctrl 键。
- .alt: 用于监听 Alt 键。
- .shift: 用于监听 Shift 键。
- .meta 或 .cmd: 用于监听 Meta 键 (Command 键或 Windows 键)。
v-text 与{{}}与 v-html 区别
{{ message }}- v-text 与{{}}效果一样,不会解析 HTML,会将表达式的结果作为纯文本插入到元素中。
- 用于将表达式的结果作为 HTML 解析并插入到元素中,它可以导致XSS攻击(跨站脚本攻击)
v-on 可以绑定多个方法吗
可以。
不同事件键值对Click me 相同事件逗号分割Click me
Vue 循环的 key 作用
性能和正确渲染:使用key有助于Vue识别每个节点的唯一性,节点内容更新时,比较同一key节点的内容,Vue可以更快速和更准确地判断哪些节点需要被更新、删除或添加,从而降低渲染的成本。
什么是计算属性
- 计算属性是用来声明式的描述一个值依赖了其他的值,并且只有在依赖的属性发生变化时才会重新计算。
- 每个计算属性都包括一个 getter 和 setter 方法,它们分别负责在读取属性值和修改属性值时执行相应的逻辑。
computed: { fullName: { get() { return this.firstName + ' ' + this.lastName; }, set(value) { const names = value.split(' '); this.firstName = names[0]; this.lastName = names[1]; } } }Vue 单页面的优缺点
优点
- 快速响应和更流畅的用户体验:SPA 利用前端路由,只更新页面中的部分内容,不需要整页刷新,因此可以实现快速的用户体验。
- 减轻服务器负担: 由于不需要为每个页面请求都返回完整的 HTML 页面,服务器负担较轻。
- 代码复用: 可以通过组件化的方式将代码分割为可复用的组件,提高代码的可维护性。
缺点:
4. 首次加载较慢: SPA 首次加载需要下载这个应用必要的的 JavaScript 脚本(比如SPA的核心应用逻辑、路由配置和必要的资源),可能导致较长的首次加载时间。
5. SEO 难度较大: 搜索引擎优化对于 SPA 较为复杂,因为页面内容大部分是通过 JavaScript 动态生成的,而搜索引擎爬虫可能无法获取到这些内容。
搜索引擎优化(Search Engine Optimization)
Vuex 是什么?怎么使用?在那种场景下使用
vue中的状态管理库,主要用于管理应用程序中的共享状态(state)和对状态的操作
状态可以理解为应用中的共享的响应式数据
核心包括
- State(状态): 即应用程序的数据源,存储着应用程序中需要共享和管理的状态。
- Getter(获取器): 允许组件从Store中获取状态,类似于组件的计算属性。
- Mutation(突变): 通过提交 Mutation来改变状态,是唯一能够改变状态的地方。它们是同步的事务。
- Action(动作):类似于Mutation,但是可以包含异步操作。通过提交 Action 来触发 Mutation。
Action 负责异步逻辑,然后通过 commit 触发对应的 Mutation 来改变状态。这种分工的设计可以使代码更模块化、可维护
使用
很重要,务必能默写下来 // store.js---------------------------------------------------- import { createStore } from 'vuex'; const store = createStore({ state() { return { count: 0 }; }, mutations: { increment(state) { state.count++; } }, actions: { incrementAsync(context) { //Action 函数接收一个与 store 实例具有相同方法和属性的 context 对象 setTimeout(() => { context.commit('increment'); }, 1000); } }, getters: { doubleCount: state => state.count * 2 } }); export default store; //main.js引入store-------------------------------------------------- new Vue({ // 将 store 实例传递给 Vue 实例 store, render: h => h(App) }).$mount('#app'); //.vue中使用-------------------------------------------------------------- Increment Increment Async export default { methods: { increment() { this.$store.commit('increment'); //commit(提交)用于触发同步的状态变更(Mutation) }, incrementAsync() { this.$store.dispatch('incrementAsync'); //dispatch(分发),分发一个 Action 来处理异步逻辑 } } }$store 的$表示store是 Vue 实例上的一个默认属性.
以 $ 开头的属性和方法都是 Vue 提供的一些特殊接口,用于访问和操作 Vue 实例
比如:
this.$el:当前 Vue 实例的根 DOM 元素。 this.$data:Vue 实例的数据对象 this.$props:包含了父组件传递给当前组件的属性 this.$emit('custom-event', 'Hello from child!');用于触发当前实例上的事件。 this.$router.push('/about'); Vue Router 的实例,用于在组件中进行路由导航。 this.$route 包含当前路由信息的对象,可以访问当前路由的参数、查询参数等。使用场景
- 大型单页应用: 规模大,组件嵌套深,且有多个组件需要共享状态时,Vuex 的集中式状态管理能够更好地组织和管理应用的状态。
- 团队协作开发:使用 Vuex 能够使团队成员更容易理解和协作,因为状态是集中管理的,避免了状态散落在各个组件中导致的维护困难。
具体使用场景:登录状态,加入购物车,音乐播放
对比小程序开发中的原生状态管理
getApp().globalData.userInfo = userInfo;
Vue 中路由跳转方式(声明式/编程式)
-
声明式导航(Declarative Navigation):
Home
-
编程式导航(Programmatic Navigation):
// 在组件的方法中使用编程式导航 methods: { goToHome() { this.$router.push('/home'); } } -
带参数的路由跳转:
User
// 在编程式导航中传递参数 this.$router.push({ name: 'user', params: { userId: 123 }}); -
带查询参数的路由跳转:
Search
// 在编程式导航中传递查询参数 this.$router.push({ path: 'search', query: { keyword: 'vue' }}); 使用this.$route.query.keyword;来接收
Vue 中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
动态路由也可以叫路由传参
动态路由有 query 和 prrams 两种方式传参
Vue 路由传参的两种方式,params 和 query方式与区别
形式的区别
- /user/:id 冒号
- ?key=value 问号
用途的区别
- Params适合传递对应资源的标识符,如用户ID。
- Query适合传递一些非关键性的、可选的参数,如页面过滤条件等。
如果是传递密码,使用POST请求将敏感信息包含在HTTP的请求体中,使用HTTPS协议加密
vue 跨域的解决方式
配置代理
配置代理的目的是让前端的请求先经过开发环境的服务器,再由该服务器向后端服务器发起请求。这样,对于浏览器而言,所有请求都是发往同一个域名,就不会触发同源策略的限制,从而解决了跨域问题。
module.exports = { devServer: { proxy: { '/api': { target: 'http://api.example.com', changeOrigin: true, pathRewrite: { '^/api': '' } } } } };- '/api' 是匹配请求路径的规则,表示所有以 /api 开头的请求都会被代理。
- target: 'http://api.example.com' 表示代理到的目标地址,即后端的真实地址。
- changeOrigin: true 表示改变请求源,允许跨域。
- pathRewrite: {'^/api': ''} 表示将请求路径中的 /api 替换为空字符串,确保最终的请求路径是正确的。
这样配置后,比如前端发起的请求是 /api/data,实际上会被代理到 http://api.example.com/data,从而避免了浏览器的同源策略问题。
- 这种方式仅在开发环境中使用,因为在生产环境中应该由后端服务正确配置 CORS 头信息以解决跨域问题。
Vue 的生命周期
生命周期(Lifecycle)是指一个对象从被创建到被销毁所经历的各个阶段。给了用户在不同阶段添加自己的代码的机会。
创建、挂载、更新、销毁
- setup:
- 替换了v2中的beforeCreate和created
- 组件的入口,在组件实例创建之前执行,初始化组件的状态和行为
- onBeforeMount 和 onMounted
- 前者 未挂载到DOM上
- 后者已经挂载了
- onBeforeUpdate 和 onUpdated
- 组件更新之前和之后执行逻辑
- 监控数据的变化
- onBeforeUnmount 和 onUnmounted
- 替代了destroyed
数据的请求一般放在created 和 mounted 这两个生命周期中,他们的区别是: 1.如果数据请求不依赖于 DOM 的状态,而是在 组件实例创建时就需要获取,那么使用 created 是合适的。(例如,创建组件之前,就要请求服务器返回组件的颜色)2.如果需要在组件被挂载到页面后再进行数据请求,以确保 DOM 的可用性,那么使用 mounted 是更合适的选择。(例如 请求服务器数据然后放在某个dom组件上,需要挂载后才能获得这个dom组件)
Vue 路由的实现
//创建一个路由实例,配置路由映射关系。 Vue.use(VueRouter); const routes = [ { path: '/', component: Home }, { path: '/about', component: About }, { path: '/user/:id', component: User } //在组件中通过 $route.params.id 获取参数的值 ]; const router = new VueRouter({ routes }); //实现页面跳转 Home About路由守卫
- 路由守卫允许你在路由发生变化前、后或者是变化过程中执行一些自定义的逻辑。
- 它们是一些钩子函数,可以用于处理导航过程中的不同阶段。
-
全局前置守卫 (beforeEach):
beforeEach 被用来全局性地导航守卫,可以在路由切换前执行一些逻辑。如果在全局前置守卫中调用 next(),则导航会继续进行;如果调用 next(false),则导航会被中断;如果调用 next('/path'),则导航会被重定向到新的路径。
router.beforeEach((to, from, next) => { // 在路由切换前执行一些逻辑 if (to.meta.requiresAuth && !auth.isAuthenticated) { // 如果需要验证身份但用户未认证,重定向到登录页 //meta用于存储自定义的元信息,允许你为每个路由定义一些额外的属性 //to表示即将要进入的目标路由对象 next('/login'); } else { // 继续路由导航 next(); } }); -
全局解析守卫 (beforeResolve):
beforeResolve 类似于 beforeEach,
最大的区别在于在 beforeResolve 中,可以确保所有的组件都已经创建。适合等待异步组件解析。
什么是“异步组件解析”
有时候你希望当路由导航到 /async 路径时,才会实际加载和渲染某个组件。
component属性的值可以是一个组件对象或者一个返回组件对象的函数 在这里,component属性的值是一个函数,该函数返回一个 import() 调用, 实现了异步加载组件的效果。这是异步组件解析的一种常见用法。 const routes = [ { path: '/async', component: () => import('./AsyncComponent.vue') }, // ... ];router.beforeResolve((to, from, next) => { // 在导航确认前执行逻辑 // 适用于需要等待异步组件解析完成的情况 next(); });-
全局后置守卫 (afterEach):
afterEach 在路由切换后执行,无论导航是成功的还是失败的,都会触发。
router.afterEach((to, from) => { // 在路由切换后执行一些逻辑 }); -
路由独享的守卫:
你还可以在路由配置中直接定义守卫,这些守卫只会对特定的路由产生作用。
const routes = [ { path: '/profile', component: Profile, beforeEnter: (to, from, next) => { // 在进入 '/profile' 路由前执行逻辑 // 这里的逻辑不同于全局前置守卫 next(); } } ];
Route 与 router 区别
- “Route” 通常是指被路由器管理的一个单独的路径规则,包括路径的URL和对应的组件。
- 而 “router” 则是指整个路由系统,用于处理路由切换的逻辑,包括提供一些API比如路由守卫的钩子函数在切换时执行一些操作。
Vue 路由模式 hash 和 history,简单讲一下
Vue Router 支持两种模式:hash 模式和 history 模式。这两种模式决定了在浏览器中如何处理路由。
const router = new VueRouter({ mode: 'history'/'hash', routes: [...] });-
Hash 模式:
- URL格式: 在 hash 模式下,URL 中的路径会带有一个 # 符号,例如 http://example.com/#/about。
而在前端路由的上下文中,“Hash 模式” 实际上是指 URL 中的 hash 部分(即 # 号后面的部分)的使用。
在传统的网页中,哈希主要用于页面内锚点(锚点链接),例如 https://example.com/page#section1,其中 section1 是页面内的某个锚点。
- 特点: Hash 模式通过监听 window.location.hash 的变化来实现路由的切换。因为 hash 的改变不会导致浏览器向服务器发出请求,所以可以避免一些问题,特别是在使用单页应用(SPA)时。
- 优点: 不需要特殊的服务器配置,可以在所有的 web 服务器上运行。
- 缺点: URL 中带有 #,可能看起来不太美观;此外,由于 hash 值变化不会触发页面刷新,有些浏览器历史记录、页面跳转等功能可能受到一些限制。(浏览器的历史记录中记录的是 hash 值的变化,而不是整个 URL 的变化。这可能导致在浏览器的历史记录中看到多个相同的 URL)
-
History 模式:
- URL格式: 在 history 模式下,URL 中的路径更加自然,不带有 #,例如 http://example.com/about。要求服务器配置**,确保在任何路由下都返回同一个 HTML 页面,以防止在刷新页面时出现 404 错误。
- 优点: URL 更加美观,不带有 #,更符合传统的 URL 格式。
- 缺点: 需要特殊的服务器配置,以处理在刷新页面时的路由问题。
- URL格式: 在 hash 模式下,URL 中的路径会带有一个 # 符号,例如 http://example.com/#/about。
Vue 数据绑定的几种方式
{{ message }}//插值表达式(Interpolation)
//绑定属性(v-bind) Click me//事件绑定(v-on) //双向绑定(v-model),确保视图和数据的同步 计算属性(computed) 监听属性(watch)
Vue 注册一个全局组件
//在入口文件中 // 注册全局组件 Vue.component('my-component', MyComponent);//my-component' 是你为组件指定的全局标签名 在其他模板中使用://注册局部组件 import MyLocalComponent from './MyLocalComponent.vue'; export default { components: { 'my-local-component': MyLocalComponent } // ...其他配置 };常用库的常用组件以及属性
tedesign
按钮 分割线 input
-
-
- 替代了destroyed
- setup:
- .once: 只触发一次。事件处理函数会在第一次触发后被自动解绑
- 子向父(通过事件)

