L

LebronJames

V1

2022/01/28阅读:124主题:绿意

Vue3 基础分享


Options API 和 Setup API 生命周期的比较


Options API Hook inside setup
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated


代码逻辑位置的比较

Options API

<script>
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      typeString,
      requiredtrue
    }
  },
  data () {
    return {
      repositories: [], // 1
      filters: { }, // 3
      searchQuery'' // 2
    }
  },
  computed: {
    filteredRepositories () {  }, // 3
    repositoriesMatchingSearchQuery () { }, // 2
  },
  watch: {
    user'getUserRepositories' // 1
  },
  methods: {
    getUserRepositories () {
      // using `this.user` to fetch user repositories
    }, // 1
    updateFilters () { }, // 3
  },
  mounted () {
    this.getUserRepositories() // 1
  }
}
</script>



Mixin 的缺点


  • 很容易发生冲突:因为每个 mixin 的 property 都被合并到同一个组件中,所以为了避免 property 命名冲突,你需要了解其它mixin文件的逻辑。

  • 可重用性是有限的:我们不能向 mixin 传递任何参数来改变它的逻辑,这降低了它们在抽象逻辑方面的灵活性。



使用 setup

1
<script>
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      typeString,
      requiredtrue
    }
  },
  setup (props) {
    const { user } = toRefs(props)

    const repositories = ref([])
    const getUserRepositories = async () => {
      repositories.value = await fetchUserRepositories(user.value)
    }
    onMounted(getUserRepositories)
    watch(user, getUserRepositories)
    
    return {
      repositories,
      getUserRepositories
    }
  },
}
</script>

2

<script>
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      typeString,
      requiredtrue
    }
  },
  setup (props) {
    const { user } = toRefs(props)

    const repositories = ref([])
    const getUserRepositories = async () => {
      repositories.value = await fetchUserRepositories(user.value)
    }
    onMounted(getUserRepositories)
    watch(user, getUserRepositories)

    const searchQuery = ref('')
    const repositoriesMatchingSearchQuery = computed(() => {
      return repositories.value.filter(
        repository => repository.name.includes(searchQuery.value)
      )
    })

    return {
      repositories,
      getUserRepositories,
      searchQuery,
      repositoriesMatchingSearchQuery
    }
  },
}
</script>

抽离需要复用的逻辑

import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch } from 'vue'

export default function useUserRepositories(user{
  const repositories = ref([])
  const getUserRepositories = async () => {
    repositories.value = await fetchUserRepositories(user.value)
  }

  onMounted(getUserRepositories)
  watch(user, getUserRepositories)

  return {
    repositories,
    getUserRepositories,
  }
}



Composition API

<script>
import { toRefs } from 'vue'
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import useRepositoryFilters from '@/composables/useRepositoryFilters'
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      typeString,
      requiredtrue,
    },
  },
  setup(props, context) {
    // context.attrs Attribute (非响应式对象,等同于 $attrs)
    // context.slots 插槽 (非响应式对象,等同于 $slots)
    // context.emit 触发事件 (方法,等同于 $emit)
    // context.expose 暴露公共 property (函数)

    const { user } = toRefs(props)

    const { repositories, getUserRepositories } = useUserRepositories(user) // 1

    const { searchQuery, repositoriesMatchingSearchQuery } = useRepositoryNameSearch(repositories) // 2

    const { filters, updateFilters, filteredRepositories } = useRepositoryFilters(
      repositoriesMatchingSearchQuery,
    ) // 3

    return {
      repositories: filteredRepositories,
      getUserRepositories,
      searchQuery,
      filters,
      updateFilters,
    }
  },
}
</script>

Composition 语法糖

<script setup>
import { toRefs } from 'vue'
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import useRepositoryFilters from '@/composables/useRepositoryFilters'

const props = defineProps({
  user: {
    typeString,
    requiredtrue,
  },
})

const { user } = toRefs(props)

const { repositories, getUserRepositories } = useUserRepositories(user) // 1

const { searchQuery, repositoriesMatchingSearchQuery } = useRepositoryNameSearch(repositories) // 2

const { filters, updateFilters, filteredRepositories } = useRepositoryFilters(
  // 3
  repositoriesMatchingSearchQuery,
)
</script>



ref 和 reactive


<script setup>
import { ref, reactive } from 'vue'
const eleRef = ref()
const num = ref(1)
const info = ref({ name'Lebron' })

console.log(num) // RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: 1, _value: 1, value: 1}
console.log(num.value) // 1

console.log(info) // RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: {user: 'Lebron'}, _value: Proxy, value: Proxy}

const originalObj = {
  active'',
  loadingfalse,
  listArray(10).fill(50),
}
const responseObj = reactive(originalObj)
console.log(responseObj) 
// Proxy {active: '', loading: false, list: Array(0)} [[Handler]]: Object [[Target]]: Object [[IsRevoked]]: false
</script>







1. ref和reactive的响应式有区别吗?

2. vue2和vue3的响应式有什么区别?



























1. ref和reactive的响应式有区别吗?

  • 当ref值的类型为对象时,使用是reactive进行代理
  • reactive只能定义对象




2. vue2和vue3的响应式有什么区别?

  • vue3使用ES6内置Proxy对象进行代理,并且vue3不会逐个遍历属性进行代理,遇到值是对象才会进行嵌套代理
  • Proxy可以实现拦截和自定义操作,比如属性查找、赋值、枚举、函数调用等







vue3一些其他方面的优化


  1. 编译阶段打上Flags
  2. diff算法优化
  3. 静态提升
  4. 事件监听缓存

Flags的类型

export const enum PatchFlags {
  TEXT = 1,// 动态的文本节点
  CLASS = 1 << 1,  // 2 动态的 class
  STYLE = 1 << 2,  // 4 动态的 style
  PROPS = 1 << 3,  // 8 动态属性,不包括类名和样式
  FULL_PROPS = 1 << 4,  // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
  HYDRATE_EVENTS = 1 << 5,  // 32 表示带有事件监听器的节点
  STABLE_FRAGMENT = 1 << 6,   // 64 一个不会改变子节点顺序的 Fragment
  KEYED_FRAGMENT = 1 << 7// 128 带有 key 属性的 Fragment
  UNKEYED_FRAGMENT = 1 << 8// 256 子节点没有 key 的 Fragment
  NEED_PATCH = 1 << 9,   // 512
  DYNAMIC_SLOTS = 1 << 10,  // 动态 solt
  HOISTED = -1,  // 特殊标志是负整数表示永远不会用作 diff
  BAIL = -2 // 一个特殊的标志,指代差异算法
}



未优化前

export function render(_ctx, _cache, $props, $setup, $data, $options{
  return (_openBlock(), _createElementBlock("div"null, [
    _createElementVNode("div", { class"content" }, " LebronJames "),
    _createElementVNode("div", {
      class"item",
      onClick: _ctx.onChange
    }, " KevinDurant "8 /* PROPS */, ["onClick"])
  ]))
}



静态提升、事件监听缓存

const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", { class"content" }, " LebronJames "-1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options{
  return (_openBlock(), _createElementBlock("div"null, [
    _hoisted_1,
    _createElementVNode("div", {
      class"item",
      onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.onChange && _ctx.onChange(...args)))
    }, " KevinDurant ")
  ]))
}



diff算法优化

if (patchFlag > 0) {
  if (patchFlag & PatchFlags.FULL_PROPS) {
    patchProps(...)
  } else {       
    if (patchFlag & PatchFlags.CLASS) {
      if (oldProps.class !== newProps.class) {
        hostPatchProp(...)
      }
    }

    if (patchFlag & PatchFlags.STYLE) {
      hostPatchProp(...)
    }

    if (patchFlag & PatchFlags.PROPS) {
      for (...) {
        ...
        if (...) {
          hostPatchProp(...)
        }
      }
    }
  }

  if (patchFlag & PatchFlags.TEXT) {
    if (...) {
      hostSetElementText(...)
    }
  }
}




vue2升级vue3需要注意的breaking change


  • filter 过滤器被移除
  • .sync 语法糖被移除
  • off、$off 被移除
  • 可以使用多个 v-model
  • 在 setup 选项中 ref 需要声明对应的变量
  • v-if 比 v-for 拥有更高的优先级

分类:

后端

标签:

后端

作者介绍

L
LebronJames
V1