我的源码学习之路(十)---vue-2.6.14

125 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

前言

不甘于平庸又不努力

2023继续!!!


vue常见的一些面试问题

 ## vue单向数据流
 ## vue中keep-alive实现与使用
 ## vue中修饰符种类介绍及源码中如何定义的?
 ## vue初始化页面闪动问题
 ## vue class style绑定问题
 ## vue-loader
 
 

vue单向数据流

一般回答:

首先先说一下

  • 为啥不能是双向? 弊端数据流动不可追踪,无法保证数据源的唯一性。
  • 解释单向:祖先组件的变量传给后代组件或者兄弟组件,一直单向传递下去,不用担心中途在某个地方修改了内容,导致后续组件和之前组件的内容不一样。
  • vue中如何使用双向数据流
    • props传入引用类型(vue检测props只能检测基本类型的值,对于复合类型,只能检测引用地址有没有变化,而属性值变化,不会被加测到),可以利用上述特性,达到‘伪双向数据流’的目的
    • .async
<user-info :userName.sync="userNameVal"/>
// 会直接修改父组件的数据
// this.$emit('update:userName', e.target.value)
<!-- 会被扩展为: -->
<user-info :userName="userNameVal" @update:userName="val => userNameVal = val"/>

vue中keep-alive实现与使用

keep-alive组件能够缓存子组件的状态

keep-alive组件和子组件呈一种插槽的关系,keep-alive组件实例的$slots属性会保存子组件的vnode

<keep-alive>
  <component :is="view"></component>
</keep-alive>
  • keep-alive组件缓存了子组件的Vue实例和子组件上传渲染的真实DOM
  • keep-alive是如何缓存的
    • 在keep-alive组件的Vue实例中有一个cache属性,该属性是一个对象,这个属性是用来缓存子组件的vnode,vnode有个componentInstance属性,这个 componentInstance 属性就是缓存的 Vue 实例,在 componentInstance 属性中有个  **el属性,这个el 属性**,这个 el 属性是缓存的真实 DOM。

源码中 url:src/core/components/keep-alive.js

export default {
  name: 'keep-alive',
  // keep-alive是一个抽象组件,抽象组件不会渲染成Dom元素,也不会出现在父组件链中
  abstract: true,//抽象

  props: {
    include: patternTypes,// 缓存白名单,只有名字在这的才会被缓存
    exclude: patternTypes,// 缓存黑名单,只能名字在这的才会被缓存
    max: [String, Number]//设置最多可缓存多少
  },

  methods: {
    cacheVNode() {
      const { cache, keys, vnodeToCache, keyToCache } = this
      if (vnodeToCache) {
        const { tag, componentInstance, componentOptions } = vnodeToCache
        cache[keyToCache] = {
          name: getComponentName(componentOptions),
          tag,
          componentInstance,
        }
        keys.push(keyToCache)
        // prune oldest entry
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
        this.vnodeToCache = null
      }
    }
  },

  created () {
    this.cache = Object.create(null)// 用于缓存vnode的对象
    this.keys = [] //存放已缓存的vnode的key的集合
  },

  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted () {
    this.cacheVNode()
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  updated () {
    this.cacheVNode()
  },
// 组件重新渲染时,执行render获取对应的vnode
  render () {
    const slot = this.$slots.default
    const vnode: VNode = getFirstComponentChild(slot)
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // check pattern
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode // 如果不在included中或者在excluded中,直接返回
      }
// 进到这,说明这个组件是要走缓存的
      const { cache, keys } = this
      const key: ?string = vnode.key == null
        // same constructor may get registered as different local components
        // so cid alone is not enough (#3269)
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key
      if (cache[key]) { // 说明之前缓存过
        vnode.componentInstance = cache[key].componentInstance
        // make current key freshest
        remove(keys, key)//删除旧的
        keys.push(key)// 重新push 保持组件的最新
      } else {
        // delay setting the cache until update
        this.vnodeToCache = vnode
        this.keyToCache = key
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }
}

vue中修饰符种类介绍及源码中如何定义的?

vue中的修饰符有这些:

  • 表单修饰符
    • .lazy 相当于debounce的作用
    • .trim 清除空格
    • .number 输入数字、
  • 事件修饰符
    • .stop 阻止事件冒泡,相当于event.stopPropagation
    • .prevent 阻止事件的默认行为,相当于event.preventDefault
    • .self 仅当元素触发时才会触发这个事件
    • .once 只触发一次
    • .capture 使用捕获模式
    • .passive 滚动事件的默认行为 (scrolling) 将立即发生而非等待 onScroll 完成,以防其中包含 event.preventDefault()
    • .naive 让组件变成像html内置标签那样监听根元素的原生事件
  • v-bind修饰符
    • .sync: 能对props进行一个双向绑定 image.png

    • .prop 设置自定义标签属性,避免暴露数据,防止污染HTML结构 image.png

    • .camel 将命名变为驼峰命名法,如将 view-Box属性名转换为 viewBox

vue初始化页面闪动问题

[v-cloak] { display: none; }

vue class style绑定问题

  • 普通语法 <div :class='className'> 绑定一个变量
  • 对象语法
    • <div :class={ 'active': boolean,'title': boolean }> 可以多个键值对
    • <div :style={ color: dataColor, fontSize: '30px' }>
  • 数组语法
    • <div :class=[isActive, isTrue, {'active': boolean }]> 可以嵌套对象语法
    • <div :style=[isActive, isTrue]>

后记

本文仅作为自己一个阅读记录,具体还是要看大佬们的文章

准备写写vue-router

下一篇:我的源码学习之路(11)---延展vue路由