vue3 + arco-design 的组合式 api 实战

最近有个新项目要做,也很久没有学习新知识了,就想着拿这个项目学点新东西. 组合式api的目的我觉得就是要更好的组织代码逻辑.让通用逻辑更好的复用.

useDialog

1. 定义dialog组合

# composables/dialog.js
import {
  computed
} from 'vue'

// 给使用它的dialog组件定义它的props
export const dialogProps = {
  visible: {
    type: Boolean,
    required: true
  }
}

// 定义双向绑定事件
export const dialogEmits = ['update:visible']

// 使用组合
export function useDialog (props, emit) {
  const visibleModel = computed({
    get () {
      return props.visible
    },
    set (val) {
      emit('update:visible', val)
    }
  })
  return {
    visibleModel
  }
}
复制代码

2. 使用dialog组合

// xxx-dialog.vue  定义某个业务弹框
<template>
    <a-modal v-model:visible="visibleModel">
        内容
    </a-modal>
</template>

<script setup>
import {dialogProps, dialogEmits, useDialog} from '../../composables/dialog'

// 定义和组合 props emits
const props = defineProps({
  ...dialogProps,
  // 其他props
})
const emits = defineEmits([
    ...dialogEmits,
    // 其他事件
])

const {visibleModel} = useDialog(props, emits)

</script>
复制代码

一个最简单的组合就完成了.

useForm

1. 定义Form组合

import {ref} from 'vue'

// 修改了vaildate方法的Form组件, 之前的validate方法不管校验失败和成功都进到then里面,我觉得不好就改成只有校验成功才进then里面
export {bbForm as Form} from '../components/bb-form'
export {Input} from '@arco-design/web-vue'
export {InputNumber} from '@arco-design/web-vue'

export function useForm (key) {
  // 需要在模板上定义 <a-form ref="ref_form">
  const ref_form = ref(null)

  return {
    ref_form
  }
}
复制代码

2. 使用Form组合

<template>
    <bb.Form ref="ref_form" :model="form">
    </bb.Form>
</template>
<script setup>
import * as bb from '../../composables/form'

const form = ref({
  name: ''
})
const {ref_form} = bb.useForm()
// 使用ref_form.value.validate验证表单
</script>
复制代码

useFormInDialog

如果有这样一个需求, 弹框里加上表单,需要提交一些信息,需要先表单验证再提交.失败不关闭表单,成功后关闭表单. 就可以把上面定义的组合再组合一下.

1.定义useFormInDialog组合

import {ref} from 'vue'
import {Message} from '@arco-design/web-vue'
import {getErrorMessageContent} from '../utils/utils'

// visibleModel 是 useDialog 定义的
// ref_form 是 useForm 定义的
export function useFormInDialog (promise, visibleModel, ref_form = null) {
  // 需要控制的表单提交按钮的loading状态
  const okLoading = ref(false)

  // 使用beforeOk这个方式来控制弹框的显示关闭状态
  function beforeOk (done) {
    let validatePromise = ref_form ? ref_form.value.bbValidate() : Promise.resolve()
    validatePromise
      .then(() => {
        okLoading.value = true
        promise()
          .then(() => {
            okLoading.value = false
            Message.success('操作成功!')
            done()
            visibleModel ? visibleModel.value = false : ''
          })
          .catch(err => {
            okLoading.value = false
            if (Array.isArray(err) && err[0].name === 'ValidateError') {

            } else {
              Message.error(getErrorMessageContent(err))
            }
          })
      })
      .catch(err => {
        console.warn('表单校验失败!', err)
        okLoading.value = false
      })
    return false
  }

  return {
    okLoading,
    beforeOk
  }
}
复制代码

2.使用useFormInDialog组合

<template>
  <a-modal 
    v-model:visible="visibleModel" // Dialog 组合
    :ok-loading="okLoading" // FormInDialog 组合
    @before-ok="beforeOk" // FormInDialog 组合
  >
    <template #title>查看和编辑</template>
    <bb.Form ref="ref_form" :model="form"> // Form 组合
      // 具体表单组件
    </bb.Form>
  </a-modal>
</template>
        
        
        
<script setup>
import axios from 'axios'
import {inject, ref, reactive} from 'vue'
import * as bb from '../../composables/form'
import {dialogProps, dialogEmits, useDialog} from '../../composables/dialog'
import {useFormInDialog} from '../../composables/form-dialog'

// Dialog组合
const props = defineProps({
  ...dialogProps,
  uuid: {
    type: String,
    required: true
  }
})
const emits = defineEmits([
    ...dialogEmits,
    'edit-success'
])
const {visibleModel} = useDialog(props, emits)

// Form组合
const form = ref({
})
const rules = reactive({
})
const {ref_form} = bb.useForm()

// FormInDialog组合
// 只需要定义好表单的校验规则,只要写少量的业务代码就能完成复用
const {okLoading, beforeOk} = useFormInDialog(() => {
  return new Promise(async (resolve, reject) => {
    try {
      await axios.put(`具体api`, {...form.value})
      resolve()
      emits('edit-success')
    } catch (err) {
      reject(err)
    }
  })
}, visibleModel, ref_form)
</script>
复制代码

总结

组合之后的代码比我之前写vue2的时候更紧凑了. 在如何写业务代码的时候更多了一些思考.

猜你喜欢

转载自juejin.im/post/7042140530871894024
今日推荐