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

2个女人做暧暧网站免费推广网站有哪些

2个女人做暧暧网站,免费推广网站有哪些,同ip网站是怎么做的,网站制作公司网站本专栏内容均可在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/490396.html

相关文章:

  • 张家港网站建设服务免费友情链接网页
  • 怎么利用网站做外链接免费建站建站abc网站
  • 静态页面做网站seo技术软件
  • 浙江网站建设服务seo查询外链
  • 系统管理员权限怎么开网站seo工具
  • 雄安做网站的公司深圳网络推广招聘
  • 下载什么网站做吃的广州百度关键词搜索
  • 做网站15年网站seo快速排名
  • 两学一做材料上哪个网站找大连seo网站推广
  • 南京网页设计培训机构重庆seo排名方法
  • 哪些网站做渣土车租恁sem培训
  • 医疗卫生网站前置审批手机免费建网站
  • 做网站政府扶持外包公司什么意思
  • 企业管理咨询有限公司的经营范围seo关键词排行优化教程
  • 自己建设企业网站上海网站seoseodian
  • 国办网站建设要求关键词优化公司如何选择
  • 电商网站建设 平台品牌推广的具体方法
  • 建站推广公司天津网站制作系统
  • 如何做网站的充值功能百度竞价渠道代理商
  • 做网站要在工商备案吗小程序推广接单平台
  • 做网站哪家公司好苏州个人建站
  • 那些使用vue做的网站市场调研方法有哪些
  • 让建站公司做网站需要什么长沙做网络推广公司的
  • 微网站制作工具如何建立自己的网络销售
  • wordpress第三方订阅地址陕西网站关键词自然排名优化
  • 电子商务网站的主要功能百度品牌广告多少钱
  • 网站开发好不好网络营销课程培训课程
  • 中国黑色网站模板星乐seo网站关键词排名优化
  • 广东智慧团建注册登录入口seo优化中商品权重主要由什么决定
  • 网新企业网站管理系统 破解网页设计与制作软件