vue基础面试题

面试题

v-show和v-if的区别

违和v-for中药用key

描述Vue组件的生命周期(有父子组件的情况)

Vue组件如何通讯

1.父子组件通讯用属性或触发事件的方式

2.两个组件没有关系或层级比较深,用自定义事件的方式

3.Vuex的方式组件通讯

描述组件渲染和更新过程

双向数据绑定v-model的实现原理

一、vue的基本使用

1、computed & watch的去区别

  • computed计算属性,有缓存,data不变则不会从新计算
  • watch如何深度监听?  handler   true
  • watch监听引用类型,拿不到oldVal
<template>
    <div>
        <input v-model="name"/>
        <input v-model="info.city"/>
    </div>
</template>

<script>
export default {
    data() {
        return {
            name: 'ariel_bo',
            info: {
                city: '北京'
            }
        }
    },
    watch: {
        name(oldVal, val) {
            // eslint-disable-next-line
            console.log('watch name', oldVal, val) // 值类型,可正常拿到 oldVal 和 val
        },
        //深度监听
        info: {
            handler(oldVal, val) {
                // eslint-disable-next-line
                console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val
            },
            deep: true // 深度监听
        }
    }
}
</script>

2. class和style

使用动态属性

使用驼峰式写法

<template>
  <div id="app">
    <div>
     <p :class="{black: isBlack, yellow: isYellow}">使用class</p>
      <p :class="[black, yellow]">使用class数组</p>
      <p :style="styleData">styleData</p>
    </div>
  </div>
</template>


<script>

export default {
  name: 'App',
  data () {
    return {
      isBlack: true,
      isYellow: true,

      black: 'black',
      yellow: 'yellow',

      styleData: {
        fontSize: '40px',
        color: 'red',
        backgroundColor: '#ccc'
      }
    }
  },
  mounted() {
  },
  methods: {

  }
}
</script>
<style scoped>
@import './assets/styles/reset.css';
.black {
  background: #999;
}
.yellow {
  color: yellow;
}
</style>

3.条件渲染v-if v-show

  • v-if v-show用法,可使用变量,也可使用===表达式
  • v-if与v-show的区别
  • v-if和v-show的使用场景
v-show是不支持template;( template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来 )
v-show不可以和v-else一起使用;
 
其次,本质的区别:
        v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有渲染的,只是通过CSS的display属性来进行 切换;
        v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;
开发中如何进行选择呢?
        如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;
        如果不会频繁的发生切换,那么使用v-if;

 4.循环(列表)渲染

1.如何便利对象? -----也可以用v-for

2.key的总要性。不能乱写,如random和index

3.v-for和v-if不能一起使用

如下,v-for会先于v-if执行,就循环三次,然后每次都执行v-if,不建议这样

<template>
  <div id="app">
    <p>遍历数组</p>
    <ul>
      <li v-for="(item, index) in listArr" :key="item.id">
        {{index}} -- {{item.id}}  --- {{item.title}}
      </li>
    </ul>
    <p>遍历对象</p>
    <ul v-if=”flag“>
      <li v-for="(val, key, index) in listObj" :key="key">
        {{index}} ---- {{key}} ----- {{val.title}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      flag: false,
      listArr: [
        {id: 'a', title: '标题1'}, // 数据结构中最好有id值,方便使用key值
        {id: 'b', title: '标题2'},
        {id: 'c', title: '标题3'}
      ],
      listObj: {
        a: {title: '标题1'},
        b: {title: '标题2'},
        c: {title: '标题3'}
      }
    }
  }
}
</script>

5.事件

event参数,自定义参数

事件修饰符、按键修饰符

事件被绑定到了哪里?

<template>
  <div id="app">
    <p>{{ num }}</p>
    <button @click="increment1">+1</button>
    <button @click="increment2(2, $event)">+1</button>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      num: 0
    }
  },
  methods: {
    increment1(event) {
      console.log(event) // 打印的是MouseEvent对象,即原生的event对象
      console.log(event.__proto__.constructor, 'constructor----')
      console.log(event.target); //  <button>+1</button> 事件挂载的对象地方
      console.log(event.currentTarget) //  <button>+1</button> 注意,事件是被注册到当前元素的,即事件是在当前对象触发的,和 React 不一样
      this.num++;
      // 1、 event是原生的
      // 2. 事件被挂载到当前元素
      // 3. 和Dom事件一样
    },
    increment2(val, event) {
      console.log(event.target)
      this.num = this.num + val;
    },
    loadHandler() {}
  },
  mounted() {
    window.addEventListener('load', this.loadHandler)
  },
  beforeDestroy() {
    // [注意]用vue绑定事件,组件销毁时会自动解绑
    // 自己绑定的事件,需要自己销毁!!!
    window.removeEventListener('load', this.loadHandler)
  }
}
</script>

事件修饰符

按键修饰符

 6.表单

v-model

常见的表单项:textarea、checkbox、radio、select

修饰符:lazy、number、trim

<template>
  <div id="app">
    <p>输入框</p>
    {{name1}}
    <input type="text" v-model.trim="name">
    <input type="text" v-model.lazy="name1"> <!-- 当改变输入框的值时,span中的值是不会变化的(注意光标还在输入框内)
 而当输入框失去焦点时,span中的值才会改变(注意光标不在输入框内)
-->
    <input type="text" v-model.number="age">

    <p>多行文本:{{desc}}</p>
    <textarea name="" id="" v-model="desc" cols="30" rows="10"></textarea>
    <!-- 注意,<textarea>{{desc}}</textarea> 是不允许的!!! -->

    <p>复选框</p>
    <input type="checkbox" v-model="checked">

    <p>多个复选框 {{checkedName}}</p>

    <input type="checkbox" id="jack" value="Jack" v-model="checkedName">
    <label for="jack">Jack</label>
    <input type="checkbox" id="join" value="Join" v-model="checkedName">
    <label for="join">join</label>
    <input type="checkbox" id="milk" value="Milk" v-model="checkedName">
    <label for="jack">Milk</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 name="" v-model="selectedList" id="" multiple>
      <option>请选择</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">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 {
  name: 'App',
  data () {
    return {
      name: 'Ariel_Bo',
      name1: 'Ariel_Bo',
      age: 18,
      desc: '自我介绍',
      checked: true,
      checkedName: [],
      gender: 'male',
      selected: '',
      selectedList: []
    }
  },
  methods: {

  }
}
</script>

7.Vue组件使用

props和$emit

组件间通讯--自定义事件

组件生命周期

什么是Props呢?

        Props是你可以在组件上注册一些自定义的attribute

        父组件给这些attribute赋值子组件通过attribute的名称获取到对应的值

 Props有两种常见的用法:

        方式一:字符串数组,数组中的字符串就是attribute的名称;

        方式二:对象类型,对象类型我们可以在指定attribute名称的同时,指定它需要传递的类型是否是必须的、 默认值等等;

什么情况下子组件需要传递内容到父组件呢?

        当子组件有一些事件发生的时候,比如在组件中发生了点击,父组件需要切换内容;

        子组件有一些内容想要传递给父组件的时候;

我们如何完成上面的操作呢?

        首先,我们需要在子组件中定义好在某些情况下触发的事件名称

        其次,在父组件中以v-on的方式传入要监听的事件名称,并且绑定到对应的方法中;

        最后,在子组件中发生某个事件的时候,根据事件名称触发对应的事件

parent.vue

<template>
    <div>
        <Input @add="addHandler"/>
        <List :list="list" @delete="deleteHandler"/>
    </div>
</template>

<script>
import Input from './Input'
import List from './List'

export default {
    components: {
        Input,
        List
    },
    data() {
        return {
            list: [
                {
                    id: 'id-1',
                    title: '标题1'
                },
                {
                    id: 'id-2',
                    title: '标题2'
                }
            ]
        }
    },
    methods: {
        addHandler(title) {
            this.list.push({
                id: `id-${Date.now()}`,
                title
            })
        },
        deleteHandler(id) {
            this.list = this.list.filter(item => item.id !== id)
        }
    },
    created() {
        // eslint-disable-next-line
        console.log('index created')
    },
    mounted() {
        // eslint-disable-next-line
        console.log('index mounted')
    },
    beforeUpdate() {
        // eslint-disable-next-line
        console.log('index before update')
    },
    updated() {
        // eslint-disable-next-line
        console.log('index updated')
    },
}
</script>

Input.vue

<template>
    <div>
        <input type="text" v-model="title"/>
        <button @click="addTitle">add</button>
    </div>
</template>

<script>
import event from './event'

export default {
    data() {
        return {
            title: ''
        }
    },
    methods: {
        addTitle() {
            // 调用父组件的事件
            this.$emit('add', this.title)

            // 调用自定义事件
            event.$emit('onAddTitle', 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>
import event from './event'

export default {
    // props: ['list']
    props: {
        // prop 类型和默认值
        list: {
            type: Array,
            default() {
                return []
            }
        }
    },
    data() {
        return {

        }
    },
    methods: {
        deleteItem(id) {
            this.$emit('delete', id)
        },
        addTitleHandler(title) {
            // eslint-disable-next-line
            console.log('on add title', title)
        }
    },
    created() {
        // eslint-disable-next-line
        console.log('list created')
    },
    mounted() {
        // eslint-disable-next-line
        console.log('list mounted')

        // 绑定自定义事件
        event.$on('onAddTitle', this.addTitleHandler)
    },
    beforeUpdate() {
        // eslint-disable-next-line
        console.log('list before update')
    },
    updated() {
        // eslint-disable-next-line
        console.log('list updated')
    },
    beforeDestroy() {
        // 及时销毁自定义事件,否则可能造成内存泄露
        event.$off('onAddTitle', this.addTitleHandler)
    }
}
</script>

event.js   event实例

import Vue from 'vue'

export default new Vue()

8.生命周期

  • 挂载阶段
  • 更新阶段
  • 销毁阶段

父子组件之间的执行顺序

父beforeCreated ->父 created -> 父 beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

父beforeUpdate-> 子beforeUpdate -> 子updated -> 父updated

父子组件销毁顺序

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

二、vue高级特性

1.自定义V-model

官方有说到,v-model的原理其实是背后有两个操作:

        v-bind绑定value属性的值;

        v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;

2.$nextTick

  • vue是异步渲染
  • data改变之后,DOM不会立即渲染
  • $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点

如下:不加$nextTick,点击打印出来是3  6   9

加上$nextTick打印出来是 6   9   12,获取的是最新的dom节点个数

<template>
  <div>
    <ul ref="ul1">
      <li v-for="(item, index) in list" :key="index">
        {{ item }}
      </li>
    </ul>
    <button @click="addItem">添加一条</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      list: ['a', 'b', 'c']
    }
  },
  methods: {
    addItem() {
      this.list.push(`${Date.now()}`);
      this.list.push(`${Date.now()}`);
      this.list.push(`${Date.now()}`);

      // 1. 异步渲染,$nextTick待DOM渲染完再回调
      // 3. 页面渲染时,会将data的修改做整合,多次data修改只会渲染一次
      this.$nextTick(() => {
        const ulElem = this.$refs.ul1;
        console.log(ulElem.children.length);
      })
     
    }
  }
}
</script>

<style lang="scss" scoped>

</style>

3.slot

  • 基本使用
  • 作用域插槽
  • 具名插槽

1.基本使用

//slotDome.vue
<template>
    <a :href="url">
        <slot>
            默认内容,即父组件没设置内容时,这里显示
        </slot>
    </a>
</template>

<script>
export default {
    props: ['url'],
    data() {
        return {}
    }
}
</script>

 父组件中使用

<SlotDemo :url="website.url">
            {{website.title}}
        </SlotDemo>

 作用域插槽

 <ScopedSlotDemo :url="website.url">
            <template v-slot="slotProps">
                {{slotProps.slotData.title}}
            </template>
        </ScopedSlotDemo>

 具名插槽

4.动态、异步组件

动态组件

:is= “component-name” 用法

需要根据数据,动态渲染的场景。即组件类型不确定。

<!-- 动态组件 -->
        <component :is="NextTickName"/>

异步组件

import()函数

按需加载,异步加载大组件

<!-- 异步组件 -->
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>

export default {
    components: {
  
        FormDemo: () => import('../BaseUse/FormDemo'),
        
    },}

5.keep-alive 缓存组件

Vue3组件化开发:切换组件、keep-alive_米儿的博客-CSDN博客_vue3 组件切换

缓存组件

频繁切换,不需要重复渲染

Vue常见性能优化

<template>
    <div>
        <button @click="changeState('A')">A</button>
        <button @click="changeState('B')">B</button>
        <button @click="changeState('C')">C</button>

        <keep-alive> <!-- tab 切换 -->
            <KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
            <KeepAliveStageB v-if="state === 'B'"/>
            <KeepAliveStageC v-if="state === 'C'"/>
        </keep-alive>
    </div>
</template>

<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'

export default {
    components: {
        KeepAliveStageA,
        KeepAliveStageB,
        KeepAliveStageC
    },
    data() {
        return {
            state: 'A'
        }
    },
    methods: {
        changeState(state) {
            this.state = state
        }
    }
}
</script>
<template>
    <p>state A</p>
</template>

<script>
export default {
    mounted() {
        // eslint-disable-next-line
        console.log('A mounted')
    },
    destroyed() {
        // eslint-disable-next-line
        console.log('A destroyed')
    }
}
</script>

不加keep-alive每次都会走钩子函数不停的销毁和重建,

加上keep-alive的话,就不会销毁

6.mixin

  • 多个组件有相同代码逻辑,抽离出来
  • mixin并不是完美解决方案,会有一些问题
  • Vue3提出的Composition API旨在解决这些问题

问题:

变量来源不明确,不利于阅读

多个mixin可能会造成命名冲突

mixin和组件可能出现多对多的关系,复杂度较高

Mixin的合并规则

情况一:如果是data函数的返回值对象

        返回值对象默认情况下会进行合并

         如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据

抽离出的逻辑mixin.js

export default {
    data() {
        return {
            city: '北京'
        }
    },
    methods: {
        showName() {
            // eslint-disable-next-line
            console.log(this.name)
        }
    },
    mounted() {
        // eslint-disable-next-line
        console.log('mixin mounted', this.name)
    }
}

使用

<template>
    <div>
        <p>{{name}} {{major}} {{city}}</p>
        <button @click="showName">显示姓名</button>
    </div>
</template>

<script>
import myMixin from './mixin'

export default {
    mixins: [myMixin], // 可以添加多个,会自动合并起来
    data() {
        return {
            name: '双越',
            major: 'web 前端'
        }
    },
    methods: {
    },
    mounted() {
        // eslint-disable-next-line
        console.log('component mounted', this.name)
    }
}
</script>
全局混入Mixin

三、Vuex和Vue-router使用

1.Vuex

知识点:state、getters、action、mutation

用于Vue组件

  • dispatch
  • commit
  • mapState
  • mapGetters
  • mapActions
  • mapMutations

 异步操作必须在actions里

2.Vue-router使用

vue3:vue-router路由的使用_米儿的博客-CSDN博客

1.路由模式(hash,H5 history)

2.路由配置(动态路由、懒加载)

Vue-router路由模式

  • hash模式(默认),如http://abc.com/#/user/10
  • H5 history模式,如http://abc.com/user/20
  • 后者需要server端支持,因此无特殊需求可选前者

H5 history模式配置

 Vue-router路由配置 动态路由

  Vue-router路由配置 懒加载

对应import()函数导入组件,异步加载

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值