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

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()

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

      <DataUserFormv-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)"><UButtoncolor="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.mzph.cn/diannao/57989.shtml

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

相关文章

Python 判断键是否存在字典中(新手入门、实战案例)

在早期的Python2版本中&#xff0c;可以使用 dict.has_key()方法来判断一个键是否存在于字典中。 在Python3中&#xff0c;dict.has_key()方法被废弃了&#xff0c;不能再被使用。如果在Python3中尝试使用dict.has_key()方法会导致 AttributeError异常。 那在Python3中要如何判…

k8s-service详解

Service介绍 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题&#xff0c;kubernetes提供了Service资源…

关于Docker的docker engine stopped问题解决

问题图: 主要检查这两块 启用或关闭Windows功能如下图&#xff08;将没开启的开启特别是Hyper-V&#xff0c;Linux&#xff0c;虚拟机等&#xff09;&#xff1a; 然后打开任务管理器搜索Docker service将关闭状态打开 运行管理员CMD执行如下命令 重启&#xff01;&#xff01…

Uni-App-01

HBuilder安装卸载 安装 官网地址&#xff1a;https://www.dcloud.io/hbuilderx.html 下载HBuilder最新版 解压到安装目录&#xff0c;路径中不要有中文和空格 在桌面上增加快捷方式 卸载 执行reset.bat 删除HBuilder文件夹&#xff08;如果提示文件被占用&#xff0…

使用语音模块的开发智能家居产品(使用雷龙LSYT201B 语音模块)

在这篇博客中&#xff0c;我们将探讨如何使用 LSYT201B 语音模块 进行智能设备的语音交互开发。通过这个模块&#xff0c;我们可以实现智能设备的语音识别和控制功能&#xff0c;为用户带来更为便捷和现代的交互体验。 1. 语音模块介绍 LSYT201B 是一个基于“芯片算法”的语音…

Centos7.9安装MySQL(二进制)

安装包 https://downloads.mysql.com/archives/community/ mysql-8.0.39-linux-glibc2.17-x86_64.tar.xz 1.卸载MariaDB 查看 rpm -qa|grep mariadb卸载 可能名称不一样&#xff0c;记得替换 rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x86_64rpm -qa|grep mariadb 执行…

C++游戏开发中的多线程处理是否真的能够显著提高游戏性能?如果多个线程同时访问同一资源,会发生什么?如何避免数据竞争?|多线程|游戏开发|性能优化

目录 1. 多线程处理的基本概念 1.1 多线程的定义 1.2 线程的创建与管理 2. 多线程在游戏开发中的应用 2.1 渲染与物理计算 3. 多线程处理的性能提升 3.1 性能评估 3.2 任务分配策略 4. 多线程中的数据竞争 4.1 数据竞争的定义 4.2 多线程访问同一资源的后果 4.3 避…

数字后端零基础入门系列 | Innovus零基础LAB学习Day5

###Module 12 RC参数提取和时序分析 数字后端零基础入门系列 | Innovus零基础LAB学习Day4 数字后端零基础入门系列 | Innovus零基础LAB学习Day3 数字后端零基础入门系列 | Innovus零基础LAB学习Day2 数字后端零基础入门系列 | Innovus零基础LAB学习Day1 ###LAB12-1 这个章节…

六自由度机械臂模型预测控制MPC+倒立摆+二自由度机械臂

接下来三个例子教你入门mpc&#xff0c;为了体现视频的高质量&#xff0c;在倒立摆和二自由度模型预测控制方面&#xff0c;我会给出一种基于状态变量微分的实时线性化策略&#xff0c;经过这样处理的mpc实际可以看作是nmpc。 1.一阶倒立摆MPC 1.1倒立摆状态方程 1.2倒立摆状…

rabbitmq 使用注意事项

1&#xff0c;注意开启的端口号&#xff0c;一共四个端口号&#xff0c;1883是mqtt连接的端口号&#xff0c;如果没开&#xff0c;是连接不上的需要手动起mqtt插件。 //开始mqtt插件服务 rabbitmq-plugins enable rabbitmq_mqtt 2&#xff0c;15672端口是http网页登录的管理后…

深度学习模型预测控制python tensorflow 实现

DL-MPC&#xff08;Deep Learning Model Predictive Control&#xff09;是一种结合深度学习和模型预测控制的先进控制策略。其核心思想是利用深度学习模型来预测系统的未来行为&#xff0c;并通过模型预测控制来优化控制输入&#xff0c;从而实现对复杂系统的高效控制。 深度…

MATLAB实现遗传算法优化零件拆卸装配问题

零件拆卸装配问题是一个有复杂约束的优化问题&#xff0c;它涉及到零件之间的连接关系、拆卸或装配的顺序、工具的使用、操作成本。 1.假设&#xff1a; &#xff08;1&#xff09;零件完整性&#xff1a;每个零件在拆卸和装配过程中保持完整&#xff0c;不发生形变或损坏 &…

BUUCTF之web篇

第一题 [极客大挑战 2019]EasySQL 打开靶机后可以看到这是一个登陆的页面 我们可以尝试两种方式登录 弱口令爆破&#xff08;burpsuite&#xff09; 通过SQL注入里的万能密码来跳过账户和密码验证的过程 这里就需要万能密码aor true # 在这里单引号的作用是结束用户名或者密码…

Javascript基础面试题

仅学习使用&#xff0c;若有侵权将修改或删除|面试鸭 Javascript 有哪些数据类型?它们的区别是什么? 7 原始类型Undefined、Null、Boolean、Number、String、Symbol和BigInt 引用类型&#xff1a;Object(对象、函数和数组等&#xff09; 如何判断 JavaScript 变量是数组? …

《BLEU: a Method for Automatic Evaluation of Machine Translation》翻译

文章目录 0. 摘要1. 引言1.1 理由1.2 观点 2. 基准 BLEU 指标2.1 修正的 n-gram 精度2.1.1 对文本块的修正 n-gram 精度2.1.2 仅使用修正 n-gram 精度对系统进行排序2.1.3 结合修正的 n-gram 精度 2.2 句子长度2.2.1 召回率的问题2.2.2 句子简短惩罚 2.3 BLEU 细节 3. BLEU 评估…

如何在Node.js中执行解压缩文件操作

一、解压文件 1.安装依赖&#xff1a; 安装adm-zip依赖包&#xff1a;npm install adm-zip --save 安装iconv-lite依赖包&#xff1a;npm install iconv-lite --save 解压前的file文件夹结构&#xff1a; update-1.0.2.zip压缩包内容&#xff1a; 2.在depresssFile.js文件&…

鸿蒙是必经之路

少了大嘴的发布会&#xff0c;老实讲有点让人昏昏入睡。关于技术本身的东西&#xff0c;放在后面。 我想想来加把油~ 鸿蒙发布后褒贬不一&#xff0c;其中很多人不太看好鸿蒙&#xff0c;一方面是开源性、一方面是南向北向的利益问题。 不说技术的领先点&#xff0c;我只扯扯…

【网络原理】网络地址转换----NAT技术详解

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 我们在 IP协议 一文中介绍过&#xff0c;由于IPv4协议中 IP地址只有32位&#xff0c;导致最多只能表示 42亿9千万个IP地址。但我们需要通过IP地址来标识网络上的每一个设备&#x…

【p2p、分布式,区块链笔记 IPFS】go-ipfs windows系统客户端节点实现 kubo试用

Kubo &#xff08;go-IPFS&#xff09; 是最早和使用最广泛的 IPFS 实现。它包括&#xff1a; 一个 IPFS 守护程序服务器广泛的命令行工具用于控制节点的 HTTP RPC API用于向 HTTP 浏览器提供内容的 HTTP 网关 下载 https://dist.ipfs.tech/#go-ipfs 解压 初始化 C:\User…

docker-minio启动参数

完整命令 docker run -p 9000:9000 -p 9090:9090 -v /opt/minio/data:/data -d --name -d --restartalways minio -e "MINIO_ACCESS_KEYminio" -e "MINIO_SECRET_KEYminioadmin123" minio/minio server --console-address ":9090" -address &q…