关于vue3的一些前端面试题

175 阅读5分钟

1.ref()

  • 响应式对象

  • 顶级响应式对象,可以在模板中直接使用不用添加 .value,可以直接使用

  • ref() 对像更新,Vue会自动检测更新,然后更新Dom

  • 深层次的对象也可以是响应式,也会被追踪

  • shallowRef() 是ref的浅层次表现,深层次的浅套不起作用

  • triggerRef() 强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。

  • toRef() 复制reactive()内的对象变成 ref

  • toRefs() 复制reactive()内的对象变成 ref`

    const obj = reactive({ name: 'wangxuan', age: 18 })

    const rName = toRef(obj, 'name') // rName.value = 'wangxuan'

    const rObj = toRefs(obj) // rObj.name.value = 'wangxuan' // rObj.age.value = 18

2.reactive()

  • reactive()本身具有响应式,不用添加 .value

  • 深层次的对象也可以是响应式,也会被追踪

  • 深层次的对象,如果只修改了内部属性,不会触发更新,需要使用 shallowReactive(),推出深层次

  • reactive()有局限性,所以推荐使用 ref()

    • 只对对象、数组、Set、Map等具有深层次的响应,不能对 stringnumberboolean等基本类型进行响应式

    • 不能替换整个对象,整个替换会失去响应式

    • 对解构操作不友好。要想结构出到本地对象还是响应式,可以用ref() 对象包裹,例子:

      const state = reactive({ count: 0 }) // 结构出来的count就失去了响应式 const { count } = state

      // 需要这样 const state = reactive({ count: ref(0) }) // 结构出来的count是响应式 const { count } = state

3.computed

  • 计算属性的返回值也是一个ref()对象,具有响应式。

  • 计算属性会缓存,只有当依赖的响应式发生变化时才会重新计算。

  • 计算属里 不要改变其他状态、在 getter 中做异步请求或者更改 DOM,这些操作可以在watch()中完成

  • 计算属性最好只作为一个只读的属性,官方推荐。

  • 想要更改计算属性的返回值,需要重新写计算属性的getter()setter()方法,一下例子:

    const state = ref('已读') const state1 = ref('回复') // 更改计算属性的返回值 const countRef = computed({ get: () => { return state.value + ' ' + state1.value }, set: (val) => { [state.value, state1.value] = val.split(' ') } }) countRef.value = '已读 乱回' console.log(state.value) // 已读 console.log(state1.value) // 乱回

4.watch

-浅层监听

  // 监听单个属性
  watch(state, (newVal, oldVal) => {
    console.log(newVal, oldVal)
  })
  // 监听多个属性,多个属性的监听,newValue是一个位置与监听源一致的数组
  watch([state, state1], (newVal, oldVal) => {
    console.log(newVal, oldVal)
  })
  // 监听reactive对象, satae对象的任意属性都会被监听
  // 监听响应式对象的单个属性值的时候需要用getter函数的形式监听
  watch(()=> state.value, (newVal, oldVal) => {
    console.log(newVal, oldVal)
  })
  // 监听整个响应式对象
  watch(state, (newVal, oldVal) => {
    console.log(newVal, oldVal)
  })
  // 监听getter函数,函数被调用就会执行
  watch(()=> sate.value + state1.value, (newVal, oldVal) => {
    console.log(newVal, oldVal)
  })

-深层监听添加{deep: true}属性,一般不使用渐层监听其实已经带了,添加{deep: true}会遍历整个监听对象,降低性能没有必要的时候避免使用
-{immediate:true}属性可以在创建监听起的时候就触发监听器
-{once:true}属性只监听一次
-{flush:'pre'}属性在DOM更新前执行监听器
-{flush:'post'}属性在DOM更新后执行监听器
-{flush:'sync'}属性在DOM更新前执行监听器

5.watchEffect

  • 不需要指定监听源,在回调里被用到的响应式属性都会被监听

  • 想要监听的对象,在回调中多个属性被用到都会触发监听

  • watch的区别就在于不需要指定监听源,watchEffect会更高效,写法也会更简洁

  • 在异步回调中使用监听器需要手动停止监听,返回一个停止函数,调用停止函数即可停止监听

    const stop = watchEffect(() => { console.log(state.value) }) stop() // 手动停止监听

6.组件传值

  • 模版引用可以 <ChildComponent ref="childRef" />, childRef就是子组件的引用,可以访问自组件所有属性, 子组件要通过defineExpose先暴露属性值

  • 保持单项数据流

  • 双向绑定,子组件使用defineModel()声明,父组件使用v-model绑定,子组件发生改变,父组件也会变化

  • 父组件通过props属性传递数据给子组件

    // 父组件 -> 子组件 // 子组件接收 const props = defineProps({ name: String, age: Number, text: String, // 参数校验,必填与默认值 text1: { type: String, default: 'hello', required: true } })

    // 子组件 -> 父组件 const emit = defineEmits({ 'change': null, // 事件校验 'click': ()=> { return true } }) emit('change', 'hello')

    // 子组件 -> 父组件 const emit = defineEmits(['change']) emit('change', { name: 'hello', age: 18 })

7.provide/inject

  • 父组件通过provide传递数据,子组件通过inject接收数据

  • 子组件可以接收父组件传递的数据,也可以接收祖先组件传递的数据

  • 保证数据流是单向的,也可以提供更改父组件数据的方法,在子组件中调用

    // 父组件 const state = reactive({ name: 'hello', age: 18 }) provide('state', state)

    // 子组件 const state = inject('state')

8.v-if vs v-for

  • v-if 优先级更高,如果同时使用,v-if先执行
  • 不推荐同时使用

9.v-for 也可以使用 of替代in这样写更接近js的迭代器的语法

作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

JNPF可以实现应用从创建、配置、开发、测试到发布、运维、升级等完整生命周期的管理。减少了传统应用程序的代码编写量,通过图形化、可视化的界面,以拖放组件的方式,即可快速生成应用程序的产品,大幅降低了开发企业管理类软件的难度。

当然,我更建议大家成为一个全栈,不要把自己的定位局限于前端。

感谢阅读本文

如果有什么建议,请在评论中让我知道。我很乐意改进。