vue3 增删改查的不平凡

958 阅读4分钟

先看一下Demo的页面效果

zsgc.gif 虽然它是一个简单的增删改,但是我把它当作一个标准的页面来做。

目录结构:

目录.png com.png

User:当前的页面.

compoent:拆分出来的组件,

type:User页面的公共类型声明

mitt:vue3中用来做兄弟传参

UI库:elelment-Plus

插件:安装Volar(把之前的vetur给禁用掉)vue3用到ts语法,不然到处都是报错.

所有的组件都用的是 <script lang="ts" setup>语法(也推荐大家这么用,这个语法糖很甜)

type-->index.ts

因为 添加,编辑,和列表渲染都用的是这样的数据结构所以就把它单独封装起来。

图片.png

当你需要修改User这个页面的bug的时候,首先打开的肯定是index文件,当你看到一个这样的template时,bug已经解决一半了,因为它做到了所见即所得,结构非常的清晰,我们在页面看到的是三部分"按钮","列表","新增/编辑".而他的模板部分正好也是三部分。

图片.png

在vue3中模板可以有多个根节点,这样大大减少了标签套娃的现象。

使用了<script setup>引入的子组件不需要注册,直接在模板中使用

所有的api都需要在'vue'中引入

import {...} from "vue"

ref

ref:声明一个响应式的变量,在<script setup>中修改或者使用都是通过它的.value属性。在template模板中直接引用就可以。

const a = ref(0)
a.value++

{{a}}

defineProps

defineProps 用来接收父组件传过来的变量,它是一个函数,我们需要在它的参数对象中把传过来的变量'配置'一下才能使用。在script中访问title.value,template中直接访问,有时候我们想解构props,这样会让他失去响应式 可以用toRefs它会让解构出来的变量具有响应式。

const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  title: {
    type: String,
    default: "新增",
  }
})
//template
{{title}}

const { visible, title } = toRefs(props)

//script
Mitt.emit("addData", { form, title: props.title })解构前
 Mitt.emit("addData", { form, title: title.value })//解构后

这里需要注意一个小细节就是element-Plus中的dialog组件控制它显隐的属性是v-model,这导致了父组件传过来的props不能直接使用,这里用computed计算属性可以解决,

<el-dialog v-model="dialogShow" :title="title" width="30%" :before-close="handleCancel">

const dialogShow = computed(() => visible.value)

defineEmits

defineEmits用来接收父组件传过来的函数(给父组件传值),子组件向父组件传值主要是父组件传递一个函数给子组件,在子组件通过emit触发这个函数,并把参数(通信的值)传递过去。这里我们可以理解父组件传过来的函数需要用,defineEmits接收一下,下面在需要的时候,用它的返回值,直接调用,传值就可以了。因为这个emit多次被调用所以我对它封装了一下。

const emit = defineEmits(["isShow"])
//触发父组件事件
function emitIsShow(visible="false",title="新增"){
  emit("isShow", {
    visible,
    title,
  })
}

onMounted

vue3的生命周期和vue2的生命周期几乎时没有变化的,除了前面多了个on以外,我们发现大部分组合式api的特点就是,所有的逻辑都交给它的回调函数去处理,生命周期也一样。

onMounted(() => {
//从编辑页打开弹窗
  Mitt.on('editData', (row: User) => {
    emitIsShow(true, "编辑")
    Object.assign(form, row)
  })
})

reactive

reactive声明一个响应式对象,它声明的对象不能被直接赋值替换,可以通过,Object.assign(old, new)给他赋一个新值,当修改他单个属性时可以直接修改。

const formData: User = {
  name: "",
  age: "",
  hobby: ""
}
const form = reactive(formData)

const newForm = {name:"李雷",age:18,hobby:"吃饭"}
 Object.assign(form, newForm)//替换
 form.name="李雷"//修改

watch

watch它监听对象时需要用一个函数包装一下,监听单个变量则不需要

watch(() => form.hobby, (newV) => {
  if (newV) hobbyMsg.value = newV
})

const sum = ref(0)
watch(sum, (newV,oldV) => {
  ....
})

mitt

当我们在Add组件填写完表单点击确认就会把值传给List组件,这里有两种情况,编辑保存,和新增保存,所以用title来区分,这时需要用到兄弟传参,vue3中不能new Vue()。所以需要用到一个插件mitt

npm install mitt -S

yarn mitt

安装完插件在User文件夹下建一个mitt.js文件 用的时候和$Bus一样

mitt.js

import Event from 'mitt'

export default new Event()

Add.vue

import Mitt from "../mitt.js"
Mitt.emit("addData", { form, title: title.value })

List.vue

Mitt.on("addData", (data: intData) => {
    if (data.title == "新增") {
      tableData.value.push({
        ...data.form,
        id: Math.floor(Math.random() * 1000) + 100
      })
    } else {
      tableData.value.forEach((el: User, index: number) => {
        if (el.id == data.form.id) {
          tableData.value.splice(index, 1, { ...data.form })
        }
      });
    }
  })

在ts文件中不能引入js文件所以要找到项目根目录下的.d.ts文件,添加一个模块声明即可。

declare module '*.js'

Demo完整代码:点我跳转仓库地址