当前位置: 首页 > wzjs >正文

在家做的客服正规平台网站的优化从哪里进行

在家做的客服正规平台,网站的优化从哪里进行,视频分享网站开发,免费生产管理erp本专栏内容均可在Github:notes_04 找到 完整项目使用技术栈: Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 一、本节目标 本篇我们来实现右侧笔记CURD部分。 一、效果 当点击 New 按钮的时候进入编辑界面: 当点击…

本专栏内容均可在Github:notes_04 找到


完整项目使用技术栈: Nextjs15 + MySQL + Redis + Auth + Prisma + i18n + strapi + Docker + vercel

一、本节目标

本篇我们来实现右侧笔记CURD部分。

一、效果

当点击 New 按钮的时候进入编辑界面:

在这里插入图片描述

当点击具体笔记的 Edit 按钮的时候进入该笔记的编辑页面:

在这里插入图片描述

二、笔记预览

回忆下之前的路由设计,当点击 New 的时候,导航至 /note/edit 路由,当点击 Edit 的时候,导航至 /note/edit/xxxx 路由。

新增 app/note/edit/page.tsx

import NoteEditor from "../../components/NoteEditor";export default async function EditPage() {return <NoteEditor noteId={""} initialTitle="Untitled" initialBody="" />;
}

新增 app/note/edit/loading.tsx

export default function EditSkeleton() {return (<divclassName="note-editor skeleton-container"role="progressbar"aria-busy="true"><div className="note-editor-form"><div className="skeleton v-stack" style={{ height: "3rem" }} /><div className="skeleton v-stack" style={{ height: "100%" }} /></div><div className="note-editor-preview"><div className="note-editor-menu"><divclassName="skeleton skeleton--button"style={{ width: "8em", height: "2.5em" }}/><divclassName="skeleton skeleton--button"style={{ width: "8em", height: "2.5em", marginInline: "12px 0" }}/></div><divclassName="note-title skeleton"style={{ height: "3rem", width: "65%", marginInline: "12px 1em" }}/><div className="note-preview"><div className="skeleton v-stack" style={{ height: "1.5em" }} /><div className="skeleton v-stack" style={{ height: "1.5em" }} /><div className="skeleton v-stack" style={{ height: "1.5em" }} /><div className="skeleton v-stack" style={{ height: "1.5em" }} /><div className="skeleton v-stack" style={{ height: "1.5em" }} /></div></div></div>);
}

你可能会问,同级的 page.js 又没有数据请求,添加 loading.js 有什么用?

同级的 page.js 确实没有请求,但 loading.js 会将 page.js 和其 children 都包裹在 <Suspense> 中,所以 app/note/edit/[id]/page.tsx 中的请求也会触发该 loading.js

app/note/edit/[id]/page.tsx 代码如下:

import NoteEditor from "../../../components/NoteEditor";
import { getNote } from "@/lib/redis";export default async function EditPage({ params }: { params: { id: string } }) {const noteId = params.id;const note = await getNote(noteId);// 让效果更明显const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));await sleep(500);if (note === null) {return (<div className="note--empty-state"><span className="note-text--empty-state">Click a note on the left to view something! 🥺</span></div>);}return (<NoteEditornoteId={noteId}initialTitle={note.title}initialBody={note.content}/>);
}

我们抽离了一个 <NoteEditor> 组件用于实现编辑功能,app/components/NoteEditor.tsx 代码如下:

"use client";import { useState } from "react";
import NotePreview from "@/components/NotePreview";
import { useFormStatus } from "react-dom";export default function NoteEditor({ noteId, initialTitle, initialBody }) {const { pending } = useFormStatus();const [title, setTitle] = useState(initialTitle);const [body, setBody] = useState(initialBody);const isDraft = !noteId;return (<div className="note-editor"><form className="note-editor-form" autoComplete="off"><label className="offscreen" htmlFor="note-title-input">Enter a title for your note</label><inputid="note-title-input"type="text"value={title}onChange={(e) => {setTitle(e.target.value);}}/><label className="offscreen" htmlFor="note-body-input">Enter the body for your note</label><textareavalue={body}id="note-body-input"onChange={(e) => setBody(e.target.value)}/></form><div className="note-editor-preview"><form className="note-editor-menu" role="menubar"><buttonclassName="note-editor-done"disabled={pending}type="submit"role="menuitem"><imgsrc="/checkmark.svg"width="14px"height="10px"alt=""role="presentation"/>Done</button>{!isDraft && (<buttonclassName="note-editor-delete"disabled={pending}role="menuitem"><imgsrc="/cross.svg"width="10px"height="10px"alt=""role="presentation"/>Delete</button>)}</form><div className="label label--preview" role="status">Preview</div><h1 className="note-title">{title}</h1><NotePreview>{body}</NotePreview></div></div>);
}

因为需要控制输入框的状态,所以 <NoteEditor> 使用了客户端组件,我们在 <NotePreview> 中引用了 <NotePreview>组件,用于实现编辑时的实时预览功能。

三、笔记新增、更新、删除

当点击 Done 的时候,导航至对应的笔记预览页面 /note/xxxx。当点击 Delete 的时候,导航至首页。

正常开发笔记的增加、更新和删除功能,为了实现前后端交互,可能要写多个接口来实现,比如当点击删除的时候,调用删除接口,接口返回成功,前端跳转至首页。但既然我们都用了 Next.js 15 了,没必要这么麻烦,Server Actions 直接搞定,省的一个个写接口了。

修改 app/components/NoteEditor.tsx

"use client";import { useState } from "react";
import NotePreview from "./NotePreview";
import { useFormStatus } from "react-dom";
import { deleteNote, saveNote } from "../actions";
export default function NoteEditor({noteId,initialTitle,initialBody,
}: {noteId: string;initialTitle: string;initialBody: string;
}) {const { pending } = useFormStatus();const [title, setTitle] = useState(initialTitle);const [body, setBody] = useState(initialBody);const isDraft = !noteId;return (<div className="note-editor"><form className="note-editor-form" autoComplete="off"><label className="offscreen" htmlFor="note-title-input">Enter a title for your note</label><inputid="note-title-input"type="text"value={title}onChange={(e) => {setTitle(e.target.value);}}/><label className="offscreen" htmlFor="note-body-input">Enter the body for your note</label><textareavalue={body}id="note-body-input"onChange={(e) => setBody(e.target.value)}/></form><div className="note-editor-preview"><form className="note-editor-menu" role="menubar"><buttonclassName="note-editor-done"disabled={pending}type="submit"formAction={() => saveNote(noteId, title, body)}role="menuitem">Done</button>{!isDraft && (<buttonclassName="note-editor-delete"disabled={pending}formAction={() => deleteNote(noteId)}role="menuitem">Delete</button>)}</form><div className="label label--preview" role="status">Preview</div><h1 className="note-title">{title}</h1><NotePreview>{body}</NotePreview></div></div>);
}

新增:app/actions.tsx

"use server";import { redirect } from "next/navigation";
import { addNote, updateNote, delNote } from "@/lib/redis";export async function saveNote(noteId: string, title: string, body: string) {const data = JSON.stringify({title,content: body,updateTime: new Date(),});if (noteId) {updateNote(noteId, data);redirect(`/note/${noteId}`);} else {const res = await addNote(data);redirect(`/note/${res}`);}
}export async function deleteNote(noteId: string) {delNote(noteId);redirect("/");
}

至此 新增和删除可以正常运行了:

在这里插入图片描述

http://www.dtcms.com/wzjs/388756.html

相关文章:

  • 哪有做奇石网站如何优化seo技巧
  • 怎么做集合网站济宁百度推广电话
  • 买了个网站后怎么做的清博舆情系统
  • 免费网站建设网站有那些网络营销一般月薪多少
  • wordpress怎样显示文章全部列表班级优化大师网页版登录
  • joomla 1.5 网站建设基础教程网站优化排名哪家好
  • Wordpress插件完全删除福州seo公司排名
  • 做网站需要搭建服务器么培训seo
  • 怎么做8代码网站青岛招聘seo
  • 手机怎样做网站图解网站的建设流程
  • 手机网站开放配百度统计
  • 广东融都建设有限公司 公司网站网站建设与管理主要学什么
  • 做SEO公司多给网站淘宝关键词查询工具
  • 环保类网站建设网站域名ip查询
  • 建筑行业综合查询平台中山网站seo优化
  • java开发门户网站新媒体运营哪个培训机构好
  • 婚嫁网站设计最新新闻热点话题
  • WordPress短码生成器宁波企业seo推广
  • 网站网页设计怎么收费互动营销的概念
  • 网站开发合同书网络营销师有前途吗
  • 信息咨询公司网站源码怎么做市场营销和推广
  • 郑州设计网站公司营销公司排行
  • 哪个建设网站公司好搜盘 资源网
  • 企业网站搭建的优点百度网盘服务电话6988
  • 荣成做网站的公司站内推广的方法
  • 深圳网站模板百度云盘登录入口
  • 现在网站开发用什么seo综合查询站长工具关键词
  • ssh鲜花礼品网站建设挖掘关键词的工具
  • 宣传做传单的网站郑州seo顾问阿亮
  • 小学的门户网站建设网络推广员上班靠谱吗