首页IT科技前端面试题vue2020及答案(【前端面试专题】【3】Vue2)

前端面试题vue2020及答案(【前端面试专题】【3】Vue2)

时间2025-07-12 07:39:53分类IT科技浏览4393
导读:Vue 2.x Vue 基本使用 指令、插值 插值、表达式 指令、动态属性 v-html:会有 XSS 风险,会覆盖子组件...

Vue 2.x

Vue 基本使用

指令            、插值 插值                  、表达式 指令      、动态属性 v-html:会有 XSS 风险            ,会覆盖子组件 <template> <div> <p>文本插值 {{ mesage }}</p> <p>JS表达式 {{ flag ? yes : no }}</p> <!-- 只能是表达式                  ,不能是 js 语句 --> <p :id="dynamicId">动态属性 id</p> <p v-html="rawHtml"> <span>【注意】使用 v-html 之后      ,将会覆盖子元素</span> </p> </div> </template> <script> export default { data() { return { message: hello, flag: true, rawHtml: <b>这是加粗</b><i>这是斜体</i>, dynamicId: `id-${Date.now()}` } } } </script> <style scoped></style> computed 和 watch computed 有缓存         ,data 不变则不会重新计算 watch 如何深度监听? watch 监听引用类型                  ,拿不到 oldVal <template> <div> <p>num {{ num }}</p> <p>double1 {{ double1 }}</p> <input v-model="double2" /> </div> </template> <script> export default { data() { return { num: 20 } }, computed: { double1() { return this.num * 2 }, // v-model 绑定的话需要写 get set double2: { get() { return this.num * 2 }, set(val) { return this.num = val / 2 } } } } </script> <style scoped></style> <template> <div> <input v-model="name" /> <input v-model="info.city" /> </div> </template> <script> export default { data() { return { name: Jae, info: { city: xx } } }, computed: {}, watch: { name(oldVal, val) { console.log(watch name, oldVal, val) // 值类型         ,可以正常拿到 oldVal 和 val }, info: { handler(oldVal, val) { console.log(watch info, oldVal, val) // 引用类型      ,拿不到 oldVal            。因为指针相同                  ,此时已经指向了新的 val }, deep: true // 深度监听 } } } </script> <style scoped></style> class 和 style 使用动态属性 使用驼峰式写法 <template> <div> <p :class="{ black: isBack, yellow: isYellow }">使用 class</p> <p :class="[ black, yellow ]">使用 class(数组)</p> <p :style="styleData">使用 style</p> </div> </template> <script> export default { data() { return { isBack: true, isYellow: true, black: black, yellow: yellow, styleData: { fontSize: 40px, // 驼峰 color: red, backgroundColor: #ccc // 驼峰 } } } } </script> <style scoped></style> 条件渲染 v-if v-else 的用法            ,可使用变量   ,也可以使用 === 表达式 v-if 和 v-show 的区别 v-if 和 v-show 的使用场景 <template> <div> <p v-if="type === a">A</p> <p v-else-if="type === b">B</p> <p v-else>other</p> <p v-show="type === a">A by v-show</p> <p v-show="type === b">B by v-show</p> </div> </template> <script> export default { data() { return { type: a } } } </script> <style scoped></style>

如果页面上需要频繁切换渲染                  ,用 v-show;如果渲染的次数不频繁               ,用 v-if

循环(列表)渲染 如何遍历对象?—— 也可以用v-for key 的重要性 v-for 和 v-if 不能一起使用(v-for 优先级高,会执行 n 次循环后再进行 n 次 v-if 判断) <template> <div> <p>遍历数组</p> <ul> <li v-for="(item, index) in arrList" :key="item.id"> {{ index }} - {{ item.id }} - {{ item.title }} </li> </ul> <p>遍历对象</p> <ul> <li v-for="(val, key, index) in objList" :key="key"> {{ index }} - {{ key }} - {{ val.title }} </li> </ul> </div> </template> <script> export default { data() { return { flag: false, arrList: [ { id: 1, title: title1 }, { id: 2, title: title2 }, { id: 3, title: title3 } ], objList: { a: { title: title1 }, b: { title: title2 }, c: { title: title3 } } } } } </script> <style scoped></style> 事件 event 参数               ,自定义参数 事件修饰符                  ,按键修饰符 事件被绑定到哪里? <template> <div> <p>{{ num }}</p> <button @click="handleClickIncre1">+1</button> <button @click="handleClickIncre2(2, $event)">+2</button> <!-- 事件修饰符 --> <!-- 阻止单击事件继续传播 --> <a @click.stop="doSomeThing"></a> <!-- 提交事件不再重载页面 --> <form @submit.prevent="onSubmit"></form> <!-- 修饰符的串联 --> <a @click.stop.prevent="doSomeThing"></a> <!-- 只有修饰符 --> <form @submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式   ,即内部元素触发的事件先在此处理            ,然后才交由内部元素进行处理 --> <div @click.capture="doSomeThing"></div> <!-- 只当在 event.target 是当前元素自身时触发处理函数                  ,即事件不是从内部元素触发的 --> <div @click.self="doSomeThing"></div> <!-- 按键修饰符 --> <button @click.ctrl="onClick">A</button> <!-- 有且只有 Ctrl 被按下时才触发 --> <button @click.ctrl.exact="onClick">A</button> <!-- 没有任何系统修饰符被按下时才触发 --> <button @click.exact="onClick">A</button> </div> </template> <script> export default { data() { return { num: 0 } }, methods: { handleClickIncre1(event) { // 原生的 event 对象 console.log(event, event, event.__proto__.constructor) // event PointerEvent {...} PointerEvent() { [native code] } console.log(event.target) // <button>+1</button> console.log(event.currentTarget) // 事件是被注册到当前元素的 this.num ++ }, handleClickIncre2(val, event) { console.log(event.target) // <button>+2</button> this.num = this.num + val } } } </script> <style scoped></style> 表单 v-model 常见表单项 textarea checkbox radio select 修饰符 lazy number trim <template> <div> <p>输入框:{{ name }}</p> <input type="text" v-model.trim="name" /> <input type="text" v-model.lazy="name" /> <input type="text" v-model.number="age" /> <p>多行文本:{{ desc }}</p> <!-- 注意      ,不是<textarea>{{ desc }}</textarea> --> <textarea v-model="desc"></textarea> <p>复选框 {{ checked }}</p> <input type="checkbox" v-model="checked" /> <p>多个复选框 {{ checkedNames }}</p> <input type="checkbox" id="jae" value="Jae" v-model="checkedNames" /> <label for="jae">Jae</label> <input type="checkbox" id="tom" value="Tom" v-model="checkedNames" /> <label for="tom">Tom</label> <input type="checkbox" id="amy" value="Amy" v-model="checkedNames" /> <label for="amy">Amy</label> <p>单选 {{ gender }}</p> <input type="radio" id="male" value="male" v-model="gender" /> <label for="male"></label> <input type="radio" id="female" value="female" v-model="gender" /> <label for="female"></label> <p>下拉列表选择 {{ selected }}</p> <select v-model="selected"> <option disabled value="">请选择</option> <option>A</option> <option>B</option> <option>C</option> </select> <p>下拉列表多选 {{ selectedList }}</p> <select v-model="selectedList" multiple> <option disabled value="">请选择</option> <option>A</option> <option>B</option> <option>C</option> </select> </div> </template> <script> export default { data() { return { name: Jae, age: 22, desc: hello, checked: true, checkedNames: [], gender: male, selected: , selectedList: [] } } } </script> <style scoped></style>

Vue 组件使用

props 和 $emit

代码示例:

<!-- index.vue --> <template> <div> <Input @add="addHandler" /> <List :list="list" @delete="deleteHandler" /> </div> </template> <script> import Input from ./input import List from ./List export default { name: ComponentsDemo, components: { Input, List }, data() { return { list: [ { id: id-1, title: 标题1 } ] } }, methods: { addHandler(title) { this.list.push({ id: `id-${Date.now()}`, title }) }, deleteHandler(id) { console.log(1); this.list = this.list.filter(item => item.id !== id) } } } </script> <!-- Input.vue --> <template> <div> <input type="text" v-model="title"> <button @click="addTitle">add</button> </div> </template> <script> export default { name: InputName, data() { return { title: } }, methods: { addTitle() { this.$emit(add, this.title) this.title = } } } </script> <!-- List.vue --> <template> <div> <ul> <li v-for="item in list" :key="item.id"> {{ item.title }} <button @click="deleteItem(item.id)">删除</button> </li> </ul> </div> </template> <script> export default { name: ListName, props: { list: { type: Array, default: () => [] } }, data() { return {} }, methods: { deleteItem(id) { this.$emit(delete, id) } } } </script> 组件间通讯 - 自定义事件 // event.js import Vue from vue export default new Vue() <!-- Input.vue --> <script> import event from ./event export default { name: InputName, data() { return { title: } }, methods: { addTitle() { event.$emit(inputAddTitle, this.title) } } } </script> <!-- List.vue --> <script> import event from ./event export default { mounted() { event.$on(inputAddTitle, this.addTitleHandler) }, beforeDestroy() { // 及时销毁         ,否则可能造成内存泄漏 event.$off(inputAddTitle, this.addTitleHandler) }, methods: { addTitleHandler(title) { console.log(input组件emit过来的:, title) } } } </script> 组件生命周期

1)单个组件

挂载阶段(beforeCreate         、created                  、beforeMount         、mounted) 更新阶段(beforeUpdate      、updated) 销毁阶段(beforeDestroy                  、destroyed)

2)父子组件

参考上方 《prop 和 $emit》中的代码示例:

<!-- index.vue --> created() { console.log(index.vue created) }, mounted() { console.log(index.vue mounted) } <!-- List.vue --> created() { console.log(List.vue created) }, mounted() { console.log(List.vue mounted) }

输出为:

index.vue created List.vue created List.vue mounted index.vue mounted

即:父组件比子组件先创建                  ,但是父组件要等子组件渲染完才能渲染

Vue 高级特性

自定义 v-model <!-- index.vue --> <template> <div> <!-- 自定义 v-model --> <p>{{ text }}</p> <CustomVModel v-model="text" /> </div> </template> <script> import CustomVModel from ./CustomVModel.vue export default { name: AdvancedUse, components: { CustomVModel }, data() { return { text: Jae } } } </script> <!-- CustomVModel.vue --> <template> <div> <input type="text" :value="text" @input="$emit(change, $event.target.value)"> </div> </template> <script> export default { model: { prop: text, // 对应 props 中的 text event: change }, props: { text: { type: String, default: } } } </script> $nextTick Vue 是异步渲染 data 改变之后         ,DOM 不会立刻渲染 $nextTick 会在 DOM 渲染之后被触发      ,以获取最新 DOM 节点

代码示例:

<template> <div> <ul ref="ul"> <li v-for="(item, index) in list" :key="index">{{ item }}</li> </ul> <button @click="add">添加</button> </div> </template> <script> export default { name: NextTick, data() { return { list: [1, 2, 3] } }, methods: { add() { this.list.push(`${Date.now()}`) this.list.push(`${Date.now()}`) this.list.push(`${Date.now()}`) const ulEle = this.$refs.ul // 获取 DOM 元素 console.log(ulEle.childNodes.length) } } } </script>

可以看出这个输出结果不太对                  ,一开始是3个            ,点击添加后添加了3个   ,怎么输出长度还是3呢?这就是因为此时输出的 DOM 节点还是上一次的                  ,还未更新               ,如果需要得到正常的结果,就需要加上 $nextTick 确保 DOM 渲染完成:

this.$nextTick(() => { const ulEle = this.$refs.ul console.log(ulEle.childNodes.length) }) slot 基本使用

代码示例:

<!-- index.vue --> <template> <div> <SlotDemo :url="website.url"> {{ website.title }} </SlotDemo> </div> </template> <script> import SlotDemo from ./SlotDemo.vue export default { name: AdvancedUse, components: { SlotDemo }, data() { return { website: { url: https://www.bing.com, title: 搜索引擎, subTitle: 比百度好用的搜索引擎 } } } } </script> <!-- SlotDemo.vue --> <template> <div> <a :href="url"> <slot> 默认内容               ,即父组件没设置内容时                  ,显示的东西 </slot> </a> </div> </template> <script> export default { name: SlotDemo, props: { url: { type: String, defalut: } }, data() { return {} } } </script>

如果将 index.vue 中 SlotDemo 组件修改一下:

<!-- SlotDemo.vue --> <SlotDemo :url="website.url" /> 作用域插槽

代码示例:

<!-- index.vue --> <template> <div> <ScopedSlotDemo :url="website.url"> <!-- 我想在这里显示子组件中 website 中的 title   ,怎么获取得到? --> </ScopedSlotDemo> </div> </template> <script> import ScopedSlotDemo from ./ScopedSlotDemo.vue export default { name: AdvancedUse, components: { ScopedSlotDemo }, data() { return {} } } </script> <!-- ScopedSlotDemo.vue --> <template> <div> <a :href="url"> <slot :slotData="website"> <!-- 将 website 放在 slotData 中            ,这个名字可以随便取 --> {{ website.subTitle }} <!-- 默认值显示 subTitle                  ,即父组件不传值 --> </slot> </a> </div> </template> <script> export default { props: { url: { type: String, defalut: } }, data() { return { website: { url: https://www.baidu.com, title: 某搜索引擎, subTitle: 比bing不好用的搜索引擎 } } } } </script>

在父组件中的插槽接收即可:

<!-- index.vue --> <template> <div> <ScopedSlotDemo :url="website.url"> <template v-slot="{ slotData }"> <!-- 这里是解构写法      ,原来是 v-slot="slotProps"         ,这个 slotProps 也可以自己取名 --> {{ slotData.title }} <!-- 如果上面是用 slotProps 接收                  ,那这里就是写成 slotProps.slotData.title --> </template> </ScopedSlotDemo> </div> </template> <script> import ScopedSlotDemo from ./ScopedSlotDemo.vue export default { name: AdvancedUse, components: { ScopedSlotDemo }, data() { return { website: { url: https://www.bing.com, title: 搜索引擎, subTitle: 比百度好用的搜索引擎 } } } } </script> 具名插槽 <!-- NamedSlot.vue --> <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> <!-- index.vue --> <NamedSlot> <template #header> <h1>将插入 header slot 中</h1> </template> <p>将插入 main slot 中         ,即默认的未命名的 slot</p> <template #header> <h2>将插入 footer slot 中</h2> </template> </NamedSlot> 动态            、异步组件 动态组件 :is="componentName" 用法 需要根据数据      ,动态渲染的场景                  。即组件类型不确定 <template> <div> <!-- 动态组件 --> <component :is="componentName" /> </div> </template> <script> import NextTick from ./NextTick.vue export default { name: AdvancedUse, components: { NextTick }, data() { return { componentName: NextTick } } } </script> 异步组件 import() 函数 按需加载                  ,异步加载大组件 <template> <div> <!-- 异步组件 --> <NextTick v-if="showCom" /> <button @click="showCom = true">show Component</button> </div> </template> <script> // import NextTick from ./NextTick.vue 不要同步引进来 export default { name: AdvancedUse, components: { NextTick: () => import (../components/NextTick) // 动态引入 }, data() { return { showCom: false } } } </script> keep-alive 缓存组件 频繁切换            ,不需要重复渲染(比如 tabs 标签页) Vue 常见性能优化 <!-- index.vue --> <template> <div> <button @click="changeState(A)">A</button> <button @click="changeState(B)">B</button> <button @click="changeState(C)">C</button> <keepAliveStateA v-if="state === A" /> <keepAliveStateB v-if="state === B" /> <keepAliveStateC v-if="state === C" /> </div> </template> <script> import keepAliveStateA from ./keepAliveStateA import keepAliveStateB from ./keepAliveStateB import keepAliveStateC from ./keepAliveStateC export default { name: KeepAlive, components: { keepAliveStateA, keepAliveStateB, keepAliveStateC }, data() { return { state: A } }, methods: { changeState(state) { this.state = state } } } </script> <!-- keepAliveStateA.vue --> <template> <div>state A</div> </template> <script> export default { data() { return {} }, computed: {}, watch: {}, created() {}, mounted() { console.log(A mounted) }, destroyed() { console.log(A destroyed) }, } </script> <!-- keepAliveStateB.vue --> <template> <div>state B</div> </template> <script> export default { data() { return {} }, computed: {}, watch: {}, created() {}, mounted() { console.log(B mounted) }, destroyed() { console.log(B destroyed) }, } </script> <!-- keepAliveStateC.vue --> <template> <div>state C</div> </template> <script> export default { data() { return {} }, computed: {}, watch: {}, created() {}, mounted() { console.log(C mounted) }, destroyed() { console.log(C destroyed) }, } </script>

如果不需要每次切换的时候都销毁组件   ,该怎么做呢?使用 keep-alive :

<template> <div> <button @click="changeState(A)">A</button> <button @click="changeState(B)">B</button> <button @click="changeState(C)">C</button> <keep-alive> <keepAliveStateA v-if="state === A" /> <keepAliveStateB v-if="state === B" /> <keepAliveStateC v-if="state === C" /> </keep-alive> </div> </template> </script> mixin 多个组件有相同的逻辑                  ,抽离出来 mixin并不是完美的解决方案               ,会有一些问题 Vue3 提出的 Composition API 旨在解决这些问题 <!-- index.vue --> <template> <div> <p>{{ name }} {{ age }} {{ city }}</p> <button @click="showName">显示姓名</button> </div> </template> <script> import myMixin from ./mixin export default { mixins: [myMixin], // 可添加多个 data() { return { name: Jae, age: 22 } }, mounted() { console.log(index mounted) }, } </script> // mixin.js export default { data() { return { city: XXX } }, mounted() { console.log(mixin mounted) }, methods: { showName() { console.log(this.name) } } }

mixin 的问题

变量来源不明确,不利于阅读 多 mixin 可能造成命名冲突 mixin 和组件可能出现多对多的关系               ,复杂度较高

Vuex 的使用

Vuex 基本概念 state getters action mutation 用于 Vue 组件 dispatch commit mapState mapGetters mapActions mapMutations

Vue-router 的使用

路由模式(hash   、H5 history) hash 模式(默认)                  ,如 http://xxx.com/#/detail/10 H5 history 模式   ,如 http://xxx.com/detail/20 后者需要 server 端支持            ,一般无特殊需求选则前者 路由配置(动态路由                  、懒加载) const router = new VueRouter({ routes: [ // 动态路径参数                  ,以冒号开头 { path: /user/:id, component: User } ] }) export default new VueRouter({ routes: [ { path: /, component: () => import(./../components/home) } ] })

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
南山seo优化的窍门(南山seo技巧方法)