vue3.0实战踩坑|项目复盘

希望各位能明白 vue3.0 的文档就是最好的 实战文章,希望大家能先阅读文档 vue3.0文档

个人愚见 3.0 的更新 写sfc的话 可以说基本无变化,变化的点主要在于 composition api

开始

  • 年前公司开了一个新项目,普通的业务系统,心痒难耐的就上了 3.0 的船,遗憾的是工期比较紧没上ts (我倒是希望搞一搞tsx, 此处叹气),小坑有一点。不过也算是踩过来了。
  • 本文主要整理记录一些,实际开发中遇到的问题,所以vue3.0 实践大佬 可以不用继续看了,面向的是像我一样第一次使用 vue3.0 进行项目开发的同学。(会有很多官方例子)

setup 函数接收两个参数 props context

props

  • props 接收的值是具有响应式的,但也正因为如此,使用 es6 的结构后会丢失其响应式性
  • 但是 可以通过 toRefs 解构来保持其响应性
    import { toRefs } from 'vue'

    export default {
      props: {
        currentId: {
          type: String,
          default: ''
        }
      },
      setup(props) {
      const { currentId } = toRefs(props)
        console.log(currentId.value)
      }
    }

 

context 上下文

  • context上下文 向外暴露三个组件的 property: attrs(非响应对象)、slots(非响应对象)、emit
  • 文档中说 因为其不是响应式的可以放心的结构
    // 可以这样写
    export default {
      setup(props, context) {
        // Attribute (非响应式对象)
        console.log(context.attrs)

        // 插槽 (非响应式对象)
        console.log(context.slots)

        // 触发事件 (方法)
        console.log(context.emit)
      }
    }

    // 或者这样写 
    export default {
      setup(props, { attrs, slots, emit }) {
        ...
      }
    }
 

组件的注册

分为两种 同步与异步, 当然还有一些高级的东西 此处不在探讨

    // 同步(个人认为的同步)
    import test1 from './test1'
    export default {
      // 注册组件
      components: { test1 }
      }
    }

    // 异步注册 defineAsyncComponent api
    <script>
    import { ref, defineAsyncComponent } from 'vue'
    export default {
      // 注册组件
      components: {
        test1: defineAsyncComponent(() => import('./test1'))
        }
    }
    </script>

 

ref

  • ref 这个api 其实有点特殊,它作用与组件时获取的是组件自身,它又能创建响应式对象。

在setup 中获取组件的 ref 对象

  • 在组件上声明其ref
  • 在setup函数中创建 与组件ref同名ref对象 并导出
    <template>
      <!-- 同名ref -->
      <test1 ref="test1Ref"></test1>
    </template>

    <script>
    import { ref } from 'vue'
    // 导入组件
    import test1 from './test1'
    export default {
      // 注册组件
      components: { test1 },
      setup () {
        // 创建同名ref
        const test1Ref = ref(null)

        // 导出ref
        return {
          test1Ref
        }
      }
    }
    </script>

    <style scoped>

    </style>
 
  • 需要注意的是 异步注册的组件 无法正确获取ref对象

使用setup函数 与el表单结合使用时 不要让 ref 和 model 绑定同一个对象

  • 说起来这个 真的是 2.x的毛病 总喜欢 把表单的ref和model绑定一个名字
  • 这个会造成 很奇怪的现象
    • 如果页面循环调用爆栈 Avoid app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead.

    • 表单无法赋值 (因为ref 是只读对象 赋值会抛出警告)

数据监听

watch

  • 这个其实与2.0 并无太大区别,需要注意的是 其接收一个响应式对象
  • immediate 立即执行一次 无论值是否变化
  • deep 深度监听 常用与 对象
    setup (props) {
        watch(() => props.id, () => {
          console.log(props.id)
        }, { immediate: true })
        return {}
      }
 

watchEffect

  • 相比于 watch watchEffect 貌似要更智能一些,一个靠别人喂饭,一个自己做饭自己吃。
  • 官方说 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。 我的理解是 你把需要更新的字段,放在 watchEffect 函数里,字段改变时 watchEffect函数会自动执行
    const count = ref(0)

    watchEffect(() => console.log(count.value))
    // -> logs 0

    setTimeout(() => {
      count.value++
      // -> logs 1
    }, 100)
 

getCurrentInstance

  • 这是一个很神奇的属性 官网介绍 getCurrentInstance允许访问内部组件实例,这些实例对于高级用法或库创建者很有用。
  • 很重要的一个问题就是 很多人会使用这个api来获取根实例 如 const { ctx } = getCurrentInstance(), 但是 这里获取的 ctx 只用在开发模式下能获取,打包完之后是获取不到根实例的。
  • 如果项目不加 ts 开发环境可以使用 getCurrentInstance 获取的 ctx,在ts项目里 const { ctx } = getCurrentInstance() 这句会抛出一个错误 大意是 ctx不存在,因为 ctx 并未被导出。
    • image.png
  • 本来想写写具体原因有文章已经解释了咱就不费力了,用力点击 那么不能用ctx获取根实例,如何获取如 $router、$store 等对象? 请往下看?

setup 中获取 $router、$store 及el Message 等对象

  • 在模板中 仍可通过 $xxx 获取对应实例对象
  • 使用 getCurrentInstance 中的 proxy

获取 $router

    import { reactive } from 'vue'
    // 引入 vue-router
    import { useRouter, useRoute } from 'vue-router'
    export default {
      setup () {
        // 获取 router对象
        // router 大致等于  this.$router , route 同理
        // 跳转  router.push({xxx})
        const router = reactive(useRouter())
        // 获取 route对象
        const route = reactive(useRoute())

        // 正常是无需导出的
        return {
          router,
          route
        }
    }
 

获取 vuex

    import { reactive } from 'vue'
    // 引入vuex
    import { useStore } from 'vuex'
    export default {

      setup () {
        // 获取store 对象 store 等同于 this.$store
        const store = reactive(useStore())
        // 获取state 数据
        const.log(store.state.xxx)
        // 提交 commit
        const.log(store.commit('xxxxx'))
        // 正常无需导出
        return {
          store
        }
      }
 

获取 element-plus 的 Message

  • el 的 Message 文档 用力点击
  • 这个其实element-plus官网文档写的很清楚了 且element-ui 就支持 Message 按需引入
  • Message 消息提示
    image.png
  • MessageBox 弹框
    image.png
  • Notification 通知
    image.png
  • 使用例子
    import { ElMessage, ElMessageBox } from 'element-plus'
    export default {
      setup () {
        ElMessage.error('这是一个错误')
        ElMessage({ type: 'error', message: '这是一个错误' })
        // 上面这两个是一样的  看个人使用习惯
        ElMessage.success('这是一个成功的提示')
        ElMessage.info('这是一个信息提示')

        // ElMessageBox 包含 alert、 confirm、prompt 文档也有写出
        ElMessageBox.alert('这是一段内容', '标题名称', {
          confirmButtonText: '确定',
          callback: action => {
            ElMessage.info(`action: ${action}`)
          }
        })
      }
    }
 

后续会继续追加。。。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情

(1)
上一篇 2021年5月26日 下午1:05
下一篇 2021年5月26日 下午1:20

相关推荐

发表回复

登录后才能评论