希望各位能明白 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 深度监听 常用与 对象
watch
的对象一定要是响应式对象,否则可能导致异常
// 引入router
import { useRoute } from 'vue-router'
setup (props) {
watch(() => props.id, () => {
console.log(props.id)
}, { immediate: true })
const route = useRoute()
// watch route
const path = computed(() => { return route.path })
watch(() => path, () => {}, { immediate: true, deep: 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 并未被导出。 - 本来想写写具体原因有文章已经解释了咱就不费力了,用力点击 那么不能用
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
消息提示MessageBox
弹框Notification
通知- 使用例子
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}`)
}
})
}
}
bug
Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rulesn
- 这个错误的原因有很多种, 我遇到的是因为直接
watch
了route
对象,没有经过computed
,也说明这个错误不一定是因为css,可能与js有关。
// 错误的 watch route, 这样开发环境不会跑错 但是 打包后可能会有异常 const route = useRoute() // 直接 watch route watch(route, () => {}, { immediate: true, deep: true })
- 这个错误的原因有很多种, 我遇到的是因为直接
后续会继续追加。。。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情