nuxt数据库之增删改查,父组件子组件传值

news2024/11/25 18:49:10

nuxt学到数据库这里,就涉及到响应数据,父组件向子组件传值,子组件向父组件传值,最终还是需要掌握vue3的组件知识了。学习真的是一个长期的过程,不管学习了什么知识,有多少,都应该及时的记录下来,这个记录的过程,就是不断巩固自身知识的过程。之前学习其他框架的时候,不用,过两天就忘记了,当许多插件解决问题,忘记这个插件名字后,那想不起来的时候就特别痛苦了。好记忆不如烂笔头,及时记录下来吧。

ui.nuxt.com中的form章节,有很多实例代码:Form - Nuxt UI

还有,github上有很多样例代码,比如这个Table的代码: https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/TableExampleAdvanced.vue

这个Table例子看了好多遍,代码还是掌握不了啊,感觉有点难啊。Table - Nuxt UI

还是根据table上面的简单的例子,做一些修改吧,从简单的入手。

首先接着之前的文章,把drizzle orm的增删改查等做成对应的api接口路由。https://hub.nuxt.com/docs/recipes/drizzle#usage

读:select

server/api/users/index.get.ts

export default eventHandler(async () => {
  const todos = await useDrizzle().select().from(tables.users).all()

  return todos
})

增:insert

server/api/users/index.post.ts

export default eventHandler(async (event) => {
  const { name, email, password, avatar, createdAt } = await readBody(event);
  const todo = await useDrizzle()
    .insert(tables.users)
    .values({
      name,
      email,
      password,
      avatar,
      createdAt: new Date(),
    })
    .returning()
    .get();

  return todo;
});

 改:update

server/api/users/[id].patch.ts

export default eventHandler(async (event) => {
  const { id } = getRouterParams(event);
  const { completed } = await readBody(event);

  const todo = await useDrizzle()
    .update(tables.users)
    .set({
      completed,
    })
    .where(eq(tables.users.id, Number(id)))
    .returning()
    .get();

  return todo;
});

 删:delete

server/api/users/[id].delete.ts

export default eventHandler(async (event) => {
  const { id } = getRouterParams(event);

  const deletedTodo = await useDrizzle()
    .delete(tables.users)
    .where(and(eq(tables.users.id, Number(id))))
    .returning()
    .get();

  if (!deletedTodo) {
    throw createError({
      statusCode: 404,
      message: 'User not found',
    });
  }
  return deletedTodo;
});

读取的时候,都是一次性的把数据全部select出来,这个当然是不对的,不过初学的时候,先这样应付着写,之后看看怎么带参数select,进行一页一页的读取。

修改和删除的时候,是根据id来操作的,这个时候,url中就需要带上id的值这个参数了。

 

使用UTable控件把表渲染出来。第一部就是添加数据了。先进行简单的:

    const datas = {
        name: 'John Doe',
        email: 'john@example.com',
        password: 'password123',
        avatar: 'https://example.com/avatar/john.png',
        createdAt: new Date(),
}



$fetch('/api/users', {
      method: 'POST',
      body: datas,
    }).then((users: any) => {
      useToast().add({
        title: `${users.id}号添加成功!`,
        description: `
            用户名:${users.name}
            邮箱:${users.email}
            `,
      });
    });

先定义需要添加的数据,然后使用$fetch进行post添加。成功后弹出消息提示一下。 

下一步就是点击按钮,弹窗添加新用户,弹出的窗口做成控件,那就涉及到父组件向子组件传值,和子组件向父组件传值的了。

简单来说,子组件向父组件传值,就是要emit,子组件emit一个方法,在父组件用这个方法名绑定一个新的方法,父组件上的新的方法就可以执行子组件方法里的方法了,也可以执行父组件上的其他方法。

父组件向子组件传值,那就更简单了,就是子组件先定义一个属性值,不用赋初始值,在父组件上使用的时候,给这个属性值绑定一个数值,在子组件里,就可以直接获取这个属性值的值(父组件上绑定的值)。

先看子组件向父组件传值(方法):【Vue/Nuxt.js】使用Composition API实现子组件向父组件传递数据的方法 - TeHub

子组件
<script setup>
const emit = defineEmits(['hogeEvent']); //emit之外也可以
const hoge = () =>{
    emit('hogeEvent');
}
</script>
<template>
    <button type="button" @click="hoge">emit测试</button>
</template>
父组件
<script setup>
const customEvent = () =>{
  console.log('test')
}
</script>
<template>
  <ChildComponents @hogeEvent="customEvent"></ChildComponents>
</template>

在我这个user的实例中,有很多属性值,所可以emit可以多个函数值:

/**
 * 属性
 */
type Props = { modelValue: boolean; info: number };
// defineProps<Props>();
const props = defineProps<Props>();
const { info } = toRefs(props);

最后一行info被从属性值里解构出来变成响应式数据后,就可以直接使用了。


/**
 * 事件
 */
const emit = defineEmits(['parentRefresh', 'update:modelValue', 'hogeEvent']);

const onUpdate = (value: boolean) => {
  emit('update:modelValue', value);
};

const parentRefresh = () => {
  const data = { message: '这是子组件传递的数据' };
  emit('parentRefresh', data);
};

 emit可以定义多个方法,并且需要在下面进行方法的实现,如果父组件中在绑定的方法中有其他方法需要执行,比如刷新表refresh()操作,就需要在最后执行一下parentRefresh()

父组件中绑定的方法或属性值:

      <DataUserForm
        v-model="isOpen"
        @parentRefresh="showrefresh"
        @hoge-event="customEvent"
        :info="info"
      />


const isOpen = ref(false);

const info = computed(() => {
  console.log(users.value.length);

  return users.value.length;
});

/**
 * 添加用户 按钮事件
 */
const addUser = () => {
  isOpen.value = true;
};
const showrefresh = (data: any) => {
  console.log('父组件接收到的数据:', data);
  refresh();
};
const customEvent = () => {
  console.log('test');
};

isOpen是父组件上的按钮点击后显示子组件弹窗的UModal控件。info在父组件是计算select出来所有users表的数据长度,定义的时候,涉及到其他数据来源,所以需要使用computed方法,才能让数据保持响应式数据,自动同步更新。这个打印数据的动作console.log(users.value.length);,就是测试数据是否同步:

打印出来第一次的0,就是info的初始值0,第二次59,是获取数据库数据后,computed计算出来的值。或者加上服务端客服端执行判断:

const info = computed(() => {
  if (import.meta.server) {
    console.log('服务端执行:' + users.value.length);
  }
  if (import.meta.client) {
    console.log('客户端端执行:' + users.value.length);
  }
  return users.value.length;
});

这样看就比较明显了,先执行客户端,info的值为0,然后等从数据库select的值获取到后,再次同步了info的值59,客户端执行了2次。 这个就是响应式数据自动更新的动作,数据变动,就是computed再次执行一次。

refresh()刷新数据表,就是读取数据方法useLazyFetch的一个互动操作:

const { status, data, refresh } = await useLazyFetch<any>('/api/users');

const users = computed(() => {
  filtered.value.sort((a: any, b: any) => {
    return b.id - a.id;
  });
  return filtered.value;
});


  <UTable
    :columns="columns"
    :emptyState="table.emptyState"
    :loadingState="table.loadingState"
    :rows="rows"
    :loading="status === 'pending'"
    class="mb-2"
  >

 :loading="status === 'pending'" 是加载的时候,在获取数据前有个加载动画。获取的对象数组的排序方法非常有意思:

  array.sort((a: any, b: any) => {
    return b.id - a.id;
  });

这个是降序,如果想升序,return a.id-b.id就可以了。

还有一个知识点,就是node时间格式化操作,其他框架有不少操作插件,安装之后就可以进行日期格式化了,nuxt上搜索了一些插件,比如moment,time等,研究一下还是不行,最后点到new Date()上发现,typescript官方就有日期本地格式化的操作啊!!!

幸亏跟着drizzle orm 的教程添加了seed种子(https://hub.nuxt.com/docs/recipes/drizzle#seed-the-database-optional),不然还发现不了,估计要耽搁很多时间啊。

关于数据表UTable的很多操作,还需要从ui/docs/components/content/examples/TableExampleAdvanced.vue at dev · nuxt/ui · GitHub

这个源码里慢慢的学习,加上baidu和google搜索,不然很花时间啊。

还有一个,就是需要安装vscode职能插件,我安装的是 通义灵码,免费的,还是很不错的,可以提醒不同的写法。

关于创建表单数据,并提交,在ui.nuxt.com上的form栏,有不同的数据库实体类的插件,可以挑选https://ui.nuxt.com/components/form#usage

 

使用方法大同小异。 


/**
 * zod
 */
import { z } from 'zod';
import type { FormError, FormSubmitEvent } from '#ui/types';

const schema = z.object({
  name: z.string(),
  email: z.string().email('邮箱格式不正确'),
  password: z.string().min(4, '最少4位字符'),
  avatar: z.string(),
});
type Schema = z.output<typeof schema>;

const state = computed(() => {
  return reactive({
    name: z.string().parse('andu' + (info.value + 1)),
    email: z.string().parse('andu' + (info.value + 1) + '@qq.com'),
    password: z.string().parse('andu' + (info.value + 1) + 'password'),
    avatar: z.string().parse('https://picsum.photos/200/200'),
  });
});

const validate = (state: any): FormError[] => {
  const errors = [];
  if (!state.email) errors.push({ path: 'email', message: '必填项' });
  if (!state.password) errors.push({ path: 'password', message: '必填项' });
  return errors;
};

 在添加用户的时候,我想自动的给表单赋值,免得一个个手动输入太麻烦了。我的想法是获取数据长度,传给子组件,然后在名称和邮箱名后面数值+1,这样邮箱不就不重复了吗?info就是从父组件传递进来的数据长度值,怎么让表单的数据都自动更新呢?当然是要把它们放到computed里面去了。这样添加数据的是很不用一个个输入的了。

子组件最上角就是获取的数据长度。注意:这个赋值的过程,根本搜不到啊,非常非常意外的是,捣腾了好久,终于,通义灵码给自动推荐出来了!!!好意外!!!

name: z.string().parse('andu' + (info.value + 1)),

 就是这个z.string().parse()方法,原理是啥,我也不懂,就这么特么的,智能推荐出来了。AI写代码,有的时候是真牛啊。

查询、增加做完了,下面就是删除,删除最简单:


const items = (row: any) => [
  [
    {
      label: '编辑',
      icon: 'i-heroicons-pencil-square-20-solid',
    },
    {
      label: '复制',
      icon: 'i-heroicons-document-duplicate-20-solid',
    },
  ],
  [
    {
      label: '存档',
      icon: 'i-heroicons-archive-box-20-solid',
    },
    {
      label: '移动',
      icon: 'i-heroicons-arrow-right-circle-20-solid',
    },
  ],
  [
    {
      label: '删除',
      icon: 'i-heroicons-trash-20-solid',
      click: () => {
        $fetch('/api/users/' + row.id, {
          method: 'DELETE',
        }).then((users: any) => {
          useToast().add({
            title: `${users.id}号删除成功!`,
            description: `
          用户名:${users.name}<br/>
          邮箱:${users.email}
          `,
          });
        });
        refresh();
      },
    },
  ],
];



    <template #actions-data="{ row }">
      <UDropdown :items="items(row)">
        <UButton
          color="gray"
          variant="ghost"
          icon="i-heroicons-ellipsis-horizontal-20-solid"
        />
      </UDropdown>
    </template>
  </UTable>

删除是放在表格最后一列里,这个也是官网的例子有的。只要是路由有id:[id].delete,就需要在$fetch方法中的url里加上row.id。

删除后,刷新一下表refresh()。

修改还没做,应该也不难了。这几天卡在好几个点。第一个是日期格式化操作,尝试了几个插件和使用,花了不少时间。还有就是父组件和子组件之间的相互传值,这个应该是vue的基本知识,或者说是vue3的知识,网上多是Vue2的代码,搜索不少时间,慢慢尝试和总结出来传值的规律了。还有就是响应式数据问题,info的获取后,怎么在表单里让它自动更新,变成响应式数据,也是摸索学习了不少时间。最后就是ui.nuxt.com上最后Table的例子的源代码,直接照搬过来,还是没学会怎么用,感觉官方的代码好少,做的时候还多,而且官方的例子源码还不少,这要学起来,那得花多少时间啊……

时间太不够用了……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2228558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在Linux系统中使用Zabbix进行监控

如何在Linux系统中使用Zabbix进行监控 Zabbix简介 安装Zabbix 在Debian/Ubuntu系统中安装 在CentOS/RHEL系统中安装 配置Zabbix数据库 创建数据库 导入数据库 配置Zabbix服务器 访问Zabbix Web界面 完成初始配置 配置Zabbix Agent 安装Agent 配置Agent 添加主机到Zabbix 创…

《Counterfeiting Scalable Detection Image Based System for E-commerce》中文校对版

文章汉化系列目录 文章目录 文章汉化系列目录摘要CCS 概念&#xff1a;关键词1 引言2 E-CoS2.1 e-CoS架构2.2 e-CoS 模块2.2.1 图像相似度模块2.2.2 索引和搜索模块2.2.3 索引2.2.4 搜索 3 性能考量3.1 示例 13.2 示例 23.3 示例 3 4 结论致谢 摘要 电子商务中的假冒问题通过本…

前端开发设计模式——观察者模式

目录 一、定义和特点 1. 定义 2. 特点 二、实现方式 1. 使用 JavaScript 实现观察者模式的基本结构 2. 实际应用中的实现示例 三、使用场景 1. 事件处理 2. 数据绑定 3. 异步通信 4. 组件通信 四、优点 1. 解耦和灵活性 2. 实时响应和数据一致性 3. 提高代码的可…

思科--交换网络综合实验

前言 之前一直在学华为ENSP的命令&#xff0c;最近来了个实验&#xff08;被坑了&#xff09;&#xff0c;要求是用思科完成。没法子&#xff0c;就弄呗 拓扑图 实验目标 首先配置以太通道&#xff08;逻辑上的&#xff09;实现链路冗余和负载共享 在交换机接口配置trunk&#…

推荐一款开源的免费PDF编辑工具:CubePDF Utility

CubePDF Utility是一款功能强大的开源免费PDF编辑器&#xff0c;它采用了基于缩略图的界面设计&#xff0c;为用户提供了直观且高效的PDF编辑体验。该软件特别针对那些希望以简单直观方式编辑 PDF 文件的用户而设计&#xff0c;支持多种操作&#xff0c;如合并、提取、拆分、更…

探索C嘎嘎:初步接触STL

#1024程序员节&#xff5c;征文# 前言&#xff1a; 在前文小编讲述了模版初阶&#xff0c;其实讲述模版就是为了给讲STL提前铺垫&#xff0c;STL是C中很重要的一部分&#xff0c;各位读者朋友要知道它的份量&#xff0c;下面废话不多说&#xff0c;开始走进STL的世界。 目录&am…

【java】java的基本程序设计结构03-charboolean

char类型 代表 字符--符号---几何图形 大小由编码类型决定。 char是基本类型&#xff0c;但String不是。 String是Java中的一个类&#xff0c;属于引用类型; char中只能放一个字符。 char a‘a’; //任意单个字符&#xff0c;加单引号。 char a‘中’;//任意单个中文…

22-Carla AD 代理

CARLA AD agent是一种AD agent&#xff0c;它可以遵循给定的路线&#xff0c;避免与其他车辆相撞&#xff0c;并通过访问地面真实数据来遵守红绿灯的状态。CARLA AD demo使用它来提供一个如何使用ROS桥接的示例。 在内部&#xff0c;CARLA AD Agent使用单独的节点进行局部规划。…

Could not find the planner configuration ‘None‘ on the param server

moveit中运行demo.launch报错&#xff1a;Could not find the planner configuration ‘None’ on the param server 打开config文件夹下的config&#xff0c;找到ompl_planning.yaml文件&#xff0c;找到&#xff1a; arm: default_planner_config: None gripper: default_p…

微信支付宝小程序SEO优化的四大策略

在竞争激烈的小程序市场中&#xff0c;高搜索排名意味着更多的曝光机会和潜在用户。SEO即搜索引擎优化&#xff0c;对于小程序而言&#xff0c;主要指的是在微信小程序商店中提高搜索排名&#xff0c;从而增加曝光度和用户访问量。有助于小程序脱颖而出&#xff0c;提升品牌知名…

Servlet 3.0 注解开发

文章目录 Servlet3.0注解开发修改idea创建注解的servlet模板内容讲解 关于servlet3.0注解开发的疑问_配置路径省略了属性urlPatterns内容讲解内容小结 Servlet3.0注解开发 【1】问题 说明&#xff1a;之前我们都是使用web.xml进行servlet映射路径的配置。这样配置的弊端&…

如何把网页的图片批量下载?3批量下载方法有详细步骤

如何把网页的图片批量下载&#xff1f;在浏览网页时&#xff0c;我们经常会遇到内容丰富、图片繁多的页面&#xff0c;无论是欣赏美图集、研究设计案例&#xff0c;还是收集教学素材&#xff0c;这些图片往往都是宝贵的资源。然而&#xff0c;一张张手动保存不仅耗时费力&#…

Linux中SPI

参考资料 https://www.cnblogs.com/aaronLinux/p/6219146.html1.SPI 2.SPI传输 2.1传输示例 首先&#xff0c;CS0拉低选中的SPI Flash , 然后在每个时钟周期&#xff0c; DO输出对应的电平。 SPI FLASH会在每个时钟的上升沿读取D0的电平。2.2SPI模式 根据SCK的电平以及数据在…

状态机模型

文章目录 一、大盗阿福二、股票买卖 IV三、股票买卖 V四、设计密码4.1kmp题目4.2设计密码 一、大盗阿福 题目链接 #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N 1e5 10; int f[N][2]; int main() {int…

用户统计开发思路

1. 需求分析 所谓用户统计&#xff0c;实际上统计的是用户的数量。通过折线图来展示&#xff0c;上面这根蓝色线代表的是用户总量&#xff0c;下边这根绿色线代表的是新增用户数量&#xff0c;是具体到每一天。所以说用户统计主要统计两个数据&#xff0c;一个是总的用户数量&…

我开源了一个短视频应用(Go+React)|DouTok2.0 项目介绍

前言 大家好&#xff0c;这里是白泽&#xff0c;拖更了一段时间&#xff0c;抱歉。在 DouTok2.0 可以初步允许大家接入开发之后&#xff0c;这篇文章才得以出炉。 DouTok&#xff1a;一个开源的 web 端的短视频应用&#xff0c;采用微服务架构&#xff0c;包含前后端&#xff…

JavaEE初阶---网络原理之TCP篇(二)

文章目录 1.断开连接--四次挥手1.1 TCP状态1.2四次挥手的过程1.3time_wait等待1.4三次四次的总结 2.前段时间总结3.滑动窗口---传输效率机制3.1原理分析3.2丢包的处理3.3快速重传 4.流量控制---接收方安全机制4.1流量控制思路4.2剩余空间大小4.3探测包的机制 5.拥塞控制---考虑…

玩转HF/魔搭/魔乐社区

下载依赖 下载指定文件 玩转HF/魔搭/魔乐社区 1. 闯关任务 &#x1f600;Hello大家好&#xff0c;这节课为大家带来“玩转HF/魔搭/魔乐社区”的课程&#xff0c;课程任务请访问闯关任务 2. 课程内容 &#x1f600;Hello大家好&#xff0c;欢迎来到书生大模型实战营第四期…

ReactNative Fabric渲染器和组件(5)

ReactNative Fabric渲染器和组件 简述 Fabric是ReactNative中新架构最核心的模块&#xff0c;本章我们会来了解一下自定义一个Fabric组件&#xff0c;然后在JS文件中声明之后如何&#xff0c;是怎么映射到原生构建一个View的。 关于Fabric架构理念官网已经有说明了&#xff0…

DataSophon集成ApacheImpala的过程

注意: 本次安装操作系统环境为Anolis8.9(Centos7和Centos8应该也一样) DataSophon版本为DDP-1.2.1 整合的安装包我放网盘了: 通过网盘分享的文件&#xff1a;impala-4.4.1.tar.gz等2个文件 链接: https://pan.baidu.com/s/18KfkO_BEFa5gVcc16I-Yew?pwdza4k 提取码: za4k 1…