技术栈:v3 + webpack + element-plus + sass

fregment

无需根节点div

teleport

可以直接挂载到父组件外的DOM节点

Suspense

用于处理需要异步数据返回的异步组件(loading,过渡,骨架屏)

v-model变更

prop: value=> modelValue
event: input => update:modelValue

属性绑定

vue3绑定在app上
vue2绑定在vue上

比如:vue.component

  • vue2没有app概念 new Vue()的根实例作为一个app,全局只有一个,容易被污染
  • 全局配置也导致没办法在单页上做不同app实例
    1. import {createApp} from 'vue'
    2. import App from './App.vue'
    3. createAPP(App).component('comp', {
    4. render() {
    5. return h('div', 'i anm comp')
    6. }
    7. }).mount('#app')
    由于是全局的,所以不要引用就可以使用
    1. <comp></comp>

sass和sass-loader默认版本不兼容

Syntax Error: TypeError: this.getOptions is not a function

  1. sass ^1.32.12
  2. sass-loader 11.0.2

解决方案

  1. yarn add sass-loader@10

element-plus按需导入的全局引用问题

配置按需导入后全局引用存在一定性问题,有可能导致找不到引用对象
需要使用use方法代替component的方式
image.png

初始化子组件默认配置在mounted周期失效

如图所示,下图将所有的分页器抽离成全局组件

子组件在mounted周期无法获取父组件的值

调用初始化覆盖默认配置失效,
image.png

解决方案

解决方法,提前一个周期使用,直接在创建DOM后,即为created
image.png

vue3.0中的监听路由已经不能使用watch的方法

无明显优化效果

业务场景中需要路由变化时重新渲染的操作

  1. import { onBeforeRouteUpdate } from 'vue-router'
  2. onBeforeRouteUpdate(to => {
  3. console.log(to, '新路由')
  4. })
  1. import { useRoute } from 'vue-router'
  2. const route = useRoute()
  3. watch(() => route.path, (val) => {
  4. console.log('%c%s', 'color: #00a3cc', val)
  5. })

/deep/深度选择器警告

image.png

  1. // /deep/ .el-input__inner {
  2. // border:0;
  3. // }
  4. ::v-deep(.el-input__inner) {
  5. border:0;
  6. }

vue-router通配符路由重定向image.png

vuex => hooks数据数据状态维护状态

vuex可以延用v2的风格,也可以通过compotion API的方式使用, 但当前大厂的最佳实践中,很多项目已经在vue3中弃用vuex的依赖,采用hooks方式

v2-vuex

image.png

v3-vuex

image.png

v3-hooks

  1. /*
  2. * @Date: 2021-06-30 09:34:45
  3. * @LastEditTime: 2021-07-01 10:39:13
  4. */
  5. import * as IpistrAction from "@/contract/ipistr";
  6. import * as PriceAction from "@/contract/priceOracle";
  7. import { useWallet } from "@/hooks/useWallet";
  8. import { reactive } from "vue";
  9. import { useContract } from "@/hooks/useContract";
  10. const { account } = useWallet();
  11. const { contractAddress } = useContract();
  12. const balance = reactive({
  13. price: 0,
  14. amount: 0
  15. });
  16. export function useBalance() {
  17. async function fetchBalance() {
  18. if (!account.value) return;
  19. try {
  20. let result = await IpistrAction.getBalanceOf(account.value);
  21. balance.amount = result;
  22. } catch (error) {
  23. console.log(error, "fetchBalance");
  24. }
  25. }
  26. /**
  27. * @description: 获取喂价机价格
  28. * @param {*} tokenAddress
  29. * @return {*}
  30. */
  31. async function fetchPrice() {
  32. if (!contractAddress.IPISTR) return;
  33. try {
  34. let result = await PriceAction.getFeedPrice(contractAddress.IPISTR);
  35. balance.price = String(result / 10 ** 18);
  36. } catch (error) {
  37. console.log(error, "fetchPrice");
  38. }
  39. }
  40. function updateBanance() {
  41. fetchBalance();
  42. fetchPrice();
  43. }
  44. return {
  45. balance,
  46. fetchPrice,
  47. fetchBalance,
  48. updateBanance
  49. };
  50. }

父子组件通信

setup 函数可接受两个参数:propscontext

  • props 表示父组件传递过来的属性,且值为响应式的,若修改其值页面将被更新。故,props 不能进行解构,但可以使用 toRefs 进行解构,否则它将失去响应式。

  • context 上下文,里面包含 attrsslotsemit等。它不是响应式的,故可以进行解构

setup 被执行时,组件实例未被创建,只能访问到以下属性:propsattrsslotsemit。不能访问到其他选项:computedmethods等。

主要是子组件变化比较大,父组件写法和v2一致

image.png

自定义指令的写法

  1. <body>
  2. <script type="module">
  3. import { createApp } from 'https://unpkg.com/petite-vue?module'
  4. const autoFocus = (ctx) => {
  5. ctx.el.focus()
  6. }
  7. createApp().directive('auto-focus', autoFocus).mount()
  8. </script>
  9. <div v-scope>
  10. <input v-auto-focus />
  11. </div>
  12. </body>

组件封装中的上下文问题

论坛地址: https://www.yuque.com/webkubor/talking/fr89p8
image.png

配置web-components

  1. // 任何以“ion-”开头的元素都将被识别为自定义元素
  2. app.config.isCustomElement = tag => tag.startsWith('ion-')

指定一个方法,用来识别在 Vue 之外定义的自定义元素(例如,使用 Web Components API)。如果组件符合此条件,则不需要本地或全局注册,并且 Vue 不会抛出关于 Unknown custom element 的警告。
注意,所有原生 HTML 和 SVG 标记不需要在此函数中匹配——Vue 解析器自动执行此检查。

v-model与.sync功能重叠问题

vue3做了统一

  1. //父组件
  2. <componet v-model="data"></componet>
  3. // 等效于
  4. <componet :modelValue="data" @update:modelValue="data=$event"></componet>
  5. // 子组件
  6. props:['modelValue']
  7. $emit('update:modelValue', newValue)