pengenalan
Hello, apa khabar? Ini ialah Vítor, kembali dengan projek baharu untuk membantu anda meningkatkan kemahiran pengaturcaraan anda. Sudah lama sejak kali terakhir saya menerbitkan tutorial. Sejak beberapa bulan lalu, saya mengambil sedikit masa untuk berehat dan fokus kepada aktiviti lain. Dalam tempoh ini, saya membangunkan projek web kecil: blog, yang menjadi tumpuan tutorial ini.
Dalam panduan ini, kami akan mencipta bahagian hadapan halaman blog yang mampu memaparkan Markdown. Aplikasi ini akan merangkumi laluan awam dan peribadi, pengesahan pengguna dan keupayaan untuk menulis teks Markdown, menambah foto, memaparkan artikel dan banyak lagi.
Jangan teragak-agak untuk menyesuaikan aplikasi anda mengikut kehendak anda—saya juga menggalakkannya.
Anda boleh mengakses repositori untuk aplikasi ini di sini:
Gondrak08
/
platform blog
Plataform blog yang dibuat dengan Next.js/typescript.
Plataforma para blog
- Tutorial em teks
Bahan-bahan
- next-auth - biblioteca de autenticação para Next.js
- github.com/markdown-it/markdown-it - markdown biblioteca.
- github.com/sindresorhus/github-markdown-css- Para dar style ao nosso editor markdown.
- github.com/remarkjs/react-markdown - Biblioteca untuk renderizar markdown em nosso componente react.
- github.com/remarkjs/remark-react/tree/4722bdf - Pemalam untuk pengubah Markdown em React.
- codemirror.net - Komponen penyunting untuk web.
- ikon reaksi - lib de icones untuk bertindak balas.
Como usar
npm i npm run start
Pelayan
você pode encontrar or servidor dessa applicação em server
Tutorial ini juga termasuk penulisan pelayan Node.js yang akan digunakan dalam panduan ini:
Saya harap anda menikmatinya.
Selamat pengekodan!
Perpustakaan
Berikut ialah ringkasan perpustakaan yang digunakan dalam projek ini:
- next-auth - Pustaka pengesahan untuk Next.js
- github.com/markdown-it/markdown-it - Pustaka penurunan harga.
- github.com/sindresorhus/github-markdown-css - Untuk menggayakan editor Markdown kami.
- github.com/remarkjs/react-markdown - Pustaka untuk memberikan Markdown dalam komponen React kami.
- github.com/remarkjs/remark-react/tree/4722bdf - Pemalam untuk mengubah Markdown menjadi React.
- codemirror.net - Editor komponen web.
- react-icons - Pustaka ikon untuk React.
Mencipta Projek React
Kami akan menggunakan versi terkini rangka kerja Next.js, yang, pada masa menulis tutorial ini, ialah versi 13.4.
Jalankan arahan berikut untuk mencipta projek:
npm i npm run start
Semasa pemasangan, pilih tetapan templat. Dalam tutorial ini, saya akan menggunakan TypeScript sebagai bahasa pengaturcaraan dan rangka kerja Tailwind CSS untuk menggayakan aplikasi kami.
Konfigurasi
Sekarang mari pasang semua perpustakaan yang akan kami gunakan.
Penurunan harga
npx create-next-app myblog
React Remark
npm i markdown-it @types/markdown-it markdown-it-style github-markdown-css react-markdown
Codemirror
remark remark-gfm remark-react
ikon
npm @codemirror/commands @codemirror/highlight @codemirror/lang-javascript @codemirror/lang-markdown @codemirror/language @codemirror/language-data @codemirror/state @codemirror/theme-one-dark @codemirror/view
Kemudian bersihkan struktur awal pemasangan anda dengan mengalih keluar semua yang tidak akan kami gunakan.
Seni bina
Ini adalah struktur akhir aplikasi kami.
npm i react-icons @types/react-icons
Langkah Pertama
Mengkonfigurasi seterusnya.config
Dalam akar projek, dalam fail next.config.js, mari kita konfigurasikan alamat domain dari mana kita akan mengakses imej untuk artikel kita. Untuk tutorial ini, atau jika anda menggunakan pelayan tempatan, kami akan menggunakan localhost.
Pastikan anda memasukkan konfigurasi ini untuk memastikan pemuatan imej yang betul dalam aplikasi anda.
src- |- app/ | |-(pages)/ | | |- (private)/ | | | |- (home) | | | |- editArticle/[id] | | | | | | | |- newArticle | | | - (public)/ | | | - article/[id] | | | - login | | | api/ | |- auth/[...nextAuth]/route.ts | |- global.css | |- layout.tsx | | - components/ | - context/ | - interfaces/ | - lib/ | - services/ middleware.ts
Mengkonfigurasi Middleware
Dalam folder akar aplikasi src/, cipta middleware.ts untuk mengesahkan akses kepada laluan peribadi.
const nextConfig = { images: { domains: ["localhost"], }, };
Untuk mengetahui lebih lanjut tentang perisian tengah dan semua yang anda boleh lakukan dengannya, semak dokumentasi.
Mengkonfigurasi Laluan Pengesahan
Di dalam folder /app, cipta fail bernama route.ts dalam api/auth/[...nextauth]. Ia akan mengandungi konfigurasi untuk laluan kami, menyambung ke API pengesahan kami menggunakan CredentialsProvider.
Penyedia Kredensial membolehkan anda mengendalikan log masuk dengan bukti kelayakan sewenang-wenangnya, seperti nama pengguna dan kata laluan, domain, pengesahan dua faktor, peranti perkakasan, dll.
Pertama, dalam akar projek anda, buat fail .env.local dan tambahkan token yang akan digunakan sebagai rahsia kami.
npm i npm run start
Seterusnya, mari tulis sistem pengesahan kami, di mana NEXTAUTH_SECRET ini akan ditambahkan pada rahsia kami dalam fail src/app/auth/[...nextauth]/routes.ts.
npx create-next-app myblog
Pembekal Pengesahan
Mari kita cipta penyedia pengesahan, konteks, yang akan berkongsi data pengguna kami merentasi halaman laluan peribadi kami. Kami akan menggunakannya kemudian untuk membungkus salah satu fail susun atur.tsx kami.
Buat fail dalam src/context/auth-provider.tsx dengan kandungan berikut:
npm i markdown-it @types/markdown-it markdown-it-style github-markdown-css react-markdown
Gaya Global
Secara keseluruhan, dalam aplikasi kami, kami akan menggunakan CSS Tailwind untuk mencipta gaya kami. Walau bagaimanapun, di sesetengah tempat, kami akan berkongsi kelas CSS tersuai antara halaman dan komponen.
remark remark-gfm remark-react
Susun atur
Sekarang mari kita tulis reka letak, baik peribadi mahupun awam.
app/layout.tsx
npm @codemirror/commands @codemirror/highlight @codemirror/lang-javascript @codemirror/lang-markdown @codemirror/language @codemirror/language-data @codemirror/state @codemirror/theme-one-dark @codemirror/view
pages/layout.tsx
npm i react-icons @types/react-icons
Panggilan API
Aplikasi kami akan membuat beberapa panggilan ke API kami, dan anda boleh menyesuaikan aplikasi ini untuk menggunakan mana-mana API luaran. Dalam contoh kami, kami menggunakan aplikasi tempatan kami. Jika anda belum melihat tutorial bahagian belakang dan penciptaan pelayan, semaknya.
Dalam src/services/, mari tulis fungsi berikut:
- authService.ts: fungsi yang bertanggungjawab untuk mengesahkan pengguna kami pada pelayan.
src- |- app/ | |-(pages)/ | | |- (private)/ | | | |- (home) | | | |- editArticle/[id] | | | | | | | |- newArticle | | | - (public)/ | | | - article/[id] | | | - login | | | api/ | |- auth/[...nextAuth]/route.ts | |- global.css | |- layout.tsx | | - components/ | - context/ | - interfaces/ | - lib/ | - services/ middleware.ts
2.refreshAccessToken.tsx:
const nextConfig = { images: { domains: ["localhost"], }, };
- getArticles.tsx: fungsi yang bertanggungjawab untuk mengambil semua artikel yang disimpan dalam pangkalan data kami:
export { default } from "next-auth/middleware"; export const config = { matcher: ["/", "/newArticle/", "/article/", "/article/:path*"], };
- postArticle.tsx: fungsi yang bertanggungjawab untuk menyerahkan data artikel ke pelayan kami.
.env.local NEXTAUTH_SECRET = SubsTituaPorToken
- editArticle.tsx: fungsi yang bertanggungjawab untuk mengubah suai artikel tertentu dalam pangkalan data.
import NextAuth from "next-auth/next"; import type { AuthOptions } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import { authenticate } from "@/services/authService"; import refreshAccessToken from "@/services/refreshAccessToken"; export const authOptions: AuthOptions = { providers: [ CredentialsProvider({ name: "credentials", credentials: { email: { name: "email", label: "email", type: "email", placeholder: "Email", }, password: { name: "password", label: "password", type: "password", placeholder: "Password", }, }, async authorize(credentials, req) { if (typeof credentials !== "undefined") { const res = await authenticate({ email: credentials.email, password: credentials.password, }); if (typeof res !== "undefined") { return { ...res }; } else { return null; } } else { return null; } }, }), ], session: { strategy: "jwt" }, secret: process.env.NEXTAUTH_SECRET, callbacks: { async jwt({ token, user, account }: any) { if (user && account) { return { token: user?.token, accessTokenExpires: Date.now() + parseInt(user?.expiresIn, 10), refreshToken: user?.tokenRefresh, }; } if (Date.now() <ol> <li> deleteArticle.tsx: fungsi yang bertanggungjawab untuk mengalih keluar artikel tertentu daripada pangkalan data kami. </li> </ol> <pre class="brush:php;toolbar:false">'use client'; import React from 'react'; import { SessionProvider } from "next-auth/react"; export default function Provider({ children, session }: { children: React.ReactNode, session: any }): React.ReactNode { return ( <sessionprovider session="{session}"> {children} </sessionprovider> ) };
Komponen
Seterusnya, mari tulis setiap komponen yang digunakan sepanjang aplikasi.
Komponen/Navbar.tsx
Komponen ringkas dengan dua pautan navigasi.
/*global.css*/ .container { max-width: 1100px; width: 100%; margin: 0px auto; } .image-container { position: relative; width: 100%; height: 5em; padding-top: 56.25%; /* Aspect ratio 16:9 (dividindo a altura pela largura) */ } .image-container img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } @keyframes spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .loading-spinner { width: 50px; height: 50px; border: 10px solid #f3f3f3; border-top: 10px solid #293d71; border-radius: 50%; animation: spinner 1.5s linear infinite; }
Komponen/Pemuatan.tsx
Komponen pemuatan mudah, digunakan sementara menunggu panggilan API selesai.
import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; import Provider from "@/context/auth-provider"; import { getServerSession } from "next-auth"; import { authOptions } from "./api/auth/[...nextauth]/route"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Markdown Text Editor", description: "Created by ", }; export default async function RootLayout({ children, }: { children: React.ReactNode; }) { const session = await getServerSession(authOptions); return ( <provider session="{session}"> {children} </provider> ); }
Komponen/Penomboran.tsx
Komponen penomboran yang digunakan pada halaman kami memaparkan semua artikel kami, dalam laluan peribadi kami. Anda boleh mendapatkan artikel yang lebih terperinci tentang cara menulis komponen ini di sini
npm i npm run start
Komponen/ArticleCard.tsx
Komponen kad untuk memaparkan artikel bertulis.
Komponen ini juga mengandungi pautan yang akan membawa kepada kedua-dua halaman paparan artikel dan halaman untuk mengedit artikel yang ditulis sebelum ini.
npx create-next-app myblog
Komponen/ArticleList.tsx
Komponen yang bertanggungjawab untuk membuat panggilan API dan memaparkan respons.
Di sini, kami akan menggunakan dua panggilan API melalui fungsi yang kami tulis:
- getArticles.ts - mengembalikan semua artikel yang akan dipaparkan dalam komponen.
- removeArticle - mengalih keluar artikel tertentu daripada senarai kami dan daripada pelayan kami.
Kami akan menggunakan komponen Pagination.tsx, yang ditulis sebelum ini, untuk membahagikan bilangan artikel merentas halaman.
npm i markdown-it @types/markdown-it markdown-it-style github-markdown-css react-markdown
muka surat
Seterusnya, kami akan melalui setiap halaman kami, dibahagikan dengan laluan masing-masing.
Halaman Awam
Log masuk
Ini adalah halaman utama aplikasi kami. Ia adalah halaman yang mudah, dan anda boleh mengubah suainya mengikut kesesuaian anda. Pada halaman ini, kami akan menggunakan fungsi log masuk yang disediakan oleh pustaka navigasi pengesahan seterusnya.
Dalam fail src/app/pages/public/login/page.tsx.
remark remark-gfm remark-react
Halaman Artikel
Untuk mencipta halaman bacaan artikel, kami akan membangunkan halaman dinamik.
Setiap platform blog yang anda lawati berkemungkinan mempunyai halaman khusus untuk membaca artikel, boleh diakses melalui URL. Sebabnya ialah laluan halaman dinamik. Nasib baik, Next.js memudahkan perkara ini dengan kaedah AppRouter baharunya, menjadikan kehidupan kita lebih mudah.
Pertama: kita perlu mencipta laluan dalam struktur kita dengan menambahkan folder [id]. Ini akan menghasilkan struktur berikut: pages/(public)/articles/[id]/pages.tsx.
- Id sepadan dengan slug laluan navigasi kami.
- params ialah harta yang diluluskan melalui pepohon aplikasi kami yang mengandungi slug navigasi.
npm @codemirror/commands @codemirror/highlight @codemirror/lang-javascript @codemirror/lang-markdown @codemirror/language @codemirror/language-data @codemirror/state @codemirror/theme-one-dark @codemirror/view
Kedua: gunakan pustaka MarkdownIt untuk membolehkan halaman memaparkan teks dalam format Markdown.
npm i react-icons @types/react-icons
Dan akhirnya,
setelah halaman itu sedia, dengan mengakses, sebagai contoh, localhost:3000/articles/1 dalam penyemak imbas, anda akan dapat melihat artikel dengan ID yang disediakan.
Dalam kes kami, ID akan dihantar melalui navigasi apabila mengklik pada salah satu komponen ArticleCards.tsx, yang akan dipaparkan pada halaman utama laluan peribadi kami.
src- |- app/ | |-(pages)/ | | |- (private)/ | | | |- (home) | | | |- editArticle/[id] | | | | | | | |- newArticle | | | - (public)/ | | | - article/[id] | | | - login | | | api/ | |- auth/[...nextAuth]/route.ts | |- global.css | |- layout.tsx | | - components/ | - context/ | - interfaces/ | - lib/ | - services/ middleware.ts
Halaman Persendirian
Berikut ialah halaman peribadi kami, yang hanya boleh diakses setelah pengguna disahkan dalam aplikasi kami.
Rumah
Di dalam folder apl/halaman/ kami, apabila fail diisytiharkan di dalam (), ini bermakna laluan itu sepadan dengan /.
Dalam kes kami, folder (Laman Utama) merujuk kepada halaman utama laluan peribadi kami. Ia adalah halaman pertama yang pengguna lihat apabila mengesahkan ke dalam sistem. Halaman ini akan memaparkan senarai artikel daripada pangkalan data kami.
Data akan diproses oleh komponen ArticlesList.tsx kami. Jika anda belum menulis kod ini lagi, rujuk semula bahagian komponen.
Dalam apl/(halaman)/(peribadi)/(rumah)/halaman.tsx.
npm i npm run start
Artikel Baru
Ini adalah salah satu halaman paling penting dalam aplikasi kami, kerana ia membolehkan kami mendaftarkan artikel kami.
Halaman ini akan membolehkan pengguna untuk:
- Tulis artikel dalam format Markdown.
- Tetapkan imej pada artikel.
- Pratonton teks Markdown sebelum menyerahkannya ke pelayan.
Halaman menggunakan beberapa cangkuk:
- useCallback - digunakan untuk menghafal fungsi.
- useState - membolehkan anda menambah pembolehubah keadaan pada komponen kami.
- useSession - membolehkan kami menyemak sama ada pengguna disahkan dan mendapatkan token pengesahan.
Untuk ini, kami akan menggunakan dua komponen:
- TextEditor.tsx: editor teks yang kami tulis sebelum ini.
- Preview.tsx: komponen untuk memaparkan fail dalam format Markdown.
Semasa membina halaman ini, kami akan menggunakan API kami:
- POST: Menggunakan fungsi postArticle kami, kami akan menghantar artikel ke pelayan.
Kami juga akan menggunakan cangkuk useSession, yang disediakan oleh perpustakaan pengesahan seterusnya, untuk mendapatkan token pengesahan pengguna, yang akan digunakan untuk mendaftarkan artikel pada pelayan.
Ini akan melibatkan tiga panggilan API yang berbeza.
Dalam app/pages/(private)/newArticle/page.tsx.
"gunakan klien"; import React, { ChangeEvent, useCallback, useState } daripada "react"; import { useSession } daripada "next-auth/react"; import { ubah hala } daripada "next/navigation"; import postArtical daripada "@/services/postArticle"; import { AiOutlineFolderOpen } daripada "react-icons/ai"; import { RiImageEditLine } daripada "react-icons/ri"; import Imej daripada "seterusnya/imej"; import TextEditor daripada "@/components/textEditor"; import Pratonton daripada "@/komponen/PreviewText"; import { AiOutlineSend } daripada "react-icons/ai"; import { BsBodyText } daripada "react-icons/bs"; eksport fungsi lalai NewArticle(params:any) { const { data: session }: any = useSession({ dikehendaki: benar, onUnauthenticated() { redirect("/log masuk"); }, }); const [imageUrl, setImageUrl] = useState<objek>({}); const [previewImage, setPreviewImage] = useState<rentetan>(""); const [previewText, setPreviewText] = useState<boolean>(false); const [title, setTitle] = useState<rentetan>(""); const [doc, setDoc] = useState<string>("# Escreva o seu texto... n"); const handleDocChange = useCallback((newDoc: any) => { setDoc(newDoc); }, []); jika (!session?.user) mengembalikan null; const handleArticleSubmit = tak segerak (e:mana-mana) => { e.preventDefault(); token const: rentetan = session.user.token; cuba { const res = menunggu postArtical({ id: session.user.userId.toString(), token: token, imageUrl: imageUrl, tajuk: "tajuk," doc: doc, }); console.log('re--->', res); redirect('/success'); } tangkap (ralat) { console.error('Ralat menghantar artikel:', ralat); // Kendalikan ralat jika perlu ralat lontaran; } }; const handleImageChange = (e: React.ChangeEvent<htmlinputelement>) => { jika (e.target.files && e.target.files.length > 0) { fail const = e.target.files[0]; const url = URL.createObjectURL(file); setPreviewImage(url); setImageUrl(fail); } }; const handleTextPreview = (e: mana-mana) => { e.preventDefault(); setPreviewText(!previewText); }; kembali ( <section classname="w-full h-penuh min-h-skrin relatif py-8"> {previewTeks && ( <div classname="kanan mutlak-16 atas-5 p-5 sempadan-2 sempadan-slate-500 bg-slate-100 rounded-xl w-full max-w-[33em] z-30"> <pratonton doc="{doc}" tajuk="{tajuk}" previewimage="{previewImage}" onpreview="{()"> setPreviewText(!previewText)} /> </pratonton> </div> )} <form classname="relative mx-auto max-w-[700px] h-penuh min-h-[90%] w-penuh p-2 sempadan-2 sempadan-slate-200 bulat-md bg-slate-50 drop-shadow-xl flex flex-col gap-2 "> {" "} <div classname="flex justify-antara item-center"> <butang classname="border-b-2 rounded-md border-slate-500 p-2 flex items-center gap-2 hover:border-slate-400 hover:text-slate-800" onclick="{handleTextPreview}"> <bsbodytext></bsbodytext> Pratonton {" "} <butang classname="group border border-b-2 border-slate-500 rounded-md p-2 flex items-center gap-2 hover:border-slate-400 hover:text-slate-800 " onclick="{handleArticleSubmit}"> Enviar Texto <aioutlinesend classname="w-5 h-5 group-hover:text-red-500"></aioutlinesend> </butang> </butang> </div> <div classname="header-wrapper flex flex-col gap-2 "> <div classname="image-box"> {previewImage.length === 0 && ( <div classname="select-image"> <label htmluntuk="imej" classname="p-4 sempadan putus-putus sempadan-4 sempadan-slate-400 kursor-penunjuk flex flex-col item-pusat justify-center"> <aioutlinefolderopen classname="w-7 h-7"></aioutlinefolderopen> drang dan lepaskan imej </label> <masukan> <h4> Edit Artikel </h4> <p>Halaman yang serupa dengan <em>Artikel Baharu</em> (Artikel baharu), dengan beberapa perbezaan.</p> <p>Pertama, kami mentakrifkan laluan dinamik di mana kami menerima id sebagai parameter navigasi. Ini hampir sama dengan apa yang dilakukan pada halaman membaca artikel. <br> app/(pages)/(private)/editArticle/[id]/page.tsx<br> </p> <pre class="brush:php;toolbar:false">"gunakan klien"; import React, { useState, useEffect, useCallback, useRef, ChangeEvent } daripada "react"; import { useSession } daripada "next-auth/react"; import { ubah hala } daripada "next/navigation"; import Imej daripada 'next/image'; import { IArticle } daripada "@/interfaces/article.interface"; import { AiOutlineEdit } daripada "react-icons/ai"; import { BsBodyText } daripada "react-icons/bs"; import { AiOutlineFolderOpen } daripada "react-icons/ai"; import { RiImageEditLine } daripada "react-icons/ri"; import Pratonton daripada "@/komponen/PreviewText"; import TextEditor daripada "@/components/textEditor"; import Pemuatan daripada '@/komponen/Pemuatan'; import editArtical daripada "@/services/editArticle"; eksport fungsi lalai EditArticle({ params }: { params: any }) { const { data: session }: any = useSession({ dikehendaki: benar, onUnauthenticated() { redirect("/log masuk"); }, }); const id: nombor = params.id; const [artikel, setArticle] = useState<iarticle null>(null); const [imageUrl, setImageUrl] = useState<objek>({}); const [previewImage, setPreviewImage] = useState<rentetan>(""); const [previewText, setPreviewText] = useState<boolean>(false) const [title, setTitle] = useState<rentetan>(""); const [doc, setDoc] = useState<rentetan>(''); const handleDocChange = useCallback((newDoc: any) => { setDoc(newDoc); }, []); const inputRef= useRef<htmlinputelement>(null); const fetchArticle = tak segerak (id: nombor) => { cuba { respons const = tunggu ambil( `http://localhost:8080/articles/getById/${id}`, ); const jsonData = menunggu respons.json(); setArticle(jsonData); } tangkap (err) { console.log("sesuatu telah berlaku:", err); } }; useEffect(() => { jika (artikel !== null || artikel !== tidak ditentukan) { fetchArticle(id); } }, [id]); useEffect(()=>{ if(artikel != null && article.content){ setDoc(article.content) } if(artikel !=null && article.image){ setPreviewImage(`http://localhost:8080/` article.image) } },[artikel]) const handleArticleSubmit = tak segerak (e:mana-mana) => { e.preventDefault(); token const: rentetan = session.user.token; cuba{ const res = menunggu editArtical({ id: id, token: token, imageUrl:imageUrl, tajuk: tajuk, doc: doc, }); console.log('re--->',res) kembalikan semula; } tangkap (ralat){ console.log("Ralat:", ralat) } }; const handleImageClick = ()=>{ console.log('hiii') if(inputRef.current){ inputRef.current.click(); } }const handleImageChange = (e: React.ChangeEvent<htmlinputelement>) => { jika (e.target.files && e.target.files.length > 0) { fail const = e.target.files[0]; const url = URL.createObjectURL(file); setPreviewImage(url); setImageUrl(fail); } }; const handleTextPreview = (e: mana-mana) => { e.preventDefault(); setPreviewText(!previewText); console.log('hello dari pratonton!') }; if(!article) return <memuatkan></memuatkan> jika(artikel?.kandungan) kembali ( <section classname="w-penuh h-penuh min-h-skrin relatif py-8"> {previewTeks && ( <div classname="kanan mutlak-16 atas-5 p-5 sempadan-2 sempadan-slate-500 bg-slate-100 rounded-xl w-full max-w-[33em] z-30"> <pratonton doc="{doc}" tajuk="{tajuk}" previewimage="{previewImage}" onpreview="{()"> setPreviewText(!previewText)} /> </pratonton> </div> )} <div classname="relative mx-auto max-w-[700px] h-min-h-penuh-[90%] w-penuh p-2 sempadan-2 sempadan-slate-200 bulat-md bg-titik putih- shadow-md flex flex-col gap-2"> <form classname="relative mx-auto max-w-[700px] h-penuh min-h-[90%] w-penuh p-2 sempadan-2 sempadan-slate-200 bulat-md bg-slate-50 drop-shadow-md flex flex-col gap-2 "> {" "} <div classname="flex justify-antara item-center"> <butang classname="border-b-2 rounded-md border-slate-500 p-2 flex items-center gap-2 hover:border-slate-400 hover:text-slate-800" onclick="{handleTextPreview}"> <bsbodytext></bsbodytext> Pratonton {" "} <butang classname="group border border-b-2 border-slate-500 rounded-md p-2 flex items-center gap-2 hover:border-slate-400 hover:text-slate-800 " onclick="{handleArticleSubmit}"> Edit artigo <aioutlineedit classname="w-5 h-5 group-hover:text-red-500"></aioutlineedit> </butang> </butang> </div> <div classname="header-wrapper flex flex-col gap-2 "> <div classname="image-box"> {previewImage.length === 0 && ( <div classname="select-image"> <label htmlfor="image" classname="p-4 sempadan putus-putus sempadan-4 sempadan-slate-400 kursor-penunjuk flex flex-col item-pusat justify-center"> <aioutlinefolderopen classname="w-7 h-7"></aioutlinefolderopen> drang dan lepaskan imej </label> <masukan> <h2> Kesimpulan </h2> <p>Pertama, saya ingin mengucapkan terima kasih kerana meluangkan masa untuk membaca tutorial ini, dan saya juga ingin mengucapkan tahniah kepada anda kerana telah menyelesaikannya. Saya harap ia berfungsi dengan baik dan arahan langkah demi langkah mudah diikuti.</p> <p>Kedua, saya ingin menyerlahkan beberapa perkara tentang perkara yang baru kami bina. Ini adalah asas sistem blog, dan masih banyak yang perlu ditambah, seperti halaman awam yang memaparkan semua artikel, halaman pendaftaran pengguna, atau halaman ralat 404 tersuai. Jika, semasa tutorial, anda tertanya-tanya tentang halaman ini dan terlepasnya, ketahui bahawa ini adalah disengajakan. Tutorial ini memberikan anda pengalaman yang mencukupi untuk membuat halaman baharu ini sendiri, menambah banyak lagi dan melaksanakan ciri baharu.</p> <p>Terima kasih banyak-banyak, dan sehingga kali seterusnya. o/</p> </masukan> </div> </div> </div> </form> </div></section></htmlinputelement></htmlinputelement></rentetan></rentetan></boolean></rentetan></objek></iarticle>
Atas ialah kandungan terperinci Membina Papan Pemuka Blog Dinamik dengan Next.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

JavaScript adalah di tengah -tengah laman web moden kerana ia meningkatkan interaktiviti dan dinamik laman web. 1) Ia membolehkan untuk menukar kandungan tanpa menyegarkan halaman, 2) memanipulasi laman web melalui Domapi, 3) menyokong kesan interaktif kompleks seperti animasi dan drag-and-drop, 4) mengoptimumkan prestasi dan amalan terbaik untuk meningkatkan pengalaman pengguna.

C dan JavaScript mencapai interoperabilitas melalui webassembly. 1) Kod C disusun ke dalam modul WebAssembly dan diperkenalkan ke dalam persekitaran JavaScript untuk meningkatkan kuasa pengkomputeran. 2) Dalam pembangunan permainan, C mengendalikan enjin fizik dan rendering grafik, dan JavaScript bertanggungjawab untuk logik permainan dan antara muka pengguna.

JavaScript digunakan secara meluas di laman web, aplikasi mudah alih, aplikasi desktop dan pengaturcaraan sisi pelayan. 1) Dalam pembangunan laman web, JavaScript mengendalikan DOM bersama -sama dengan HTML dan CSS untuk mencapai kesan dinamik dan menyokong rangka kerja seperti JQuery dan React. 2) Melalui reaktnatif dan ionik, JavaScript digunakan untuk membangunkan aplikasi mudah alih rentas platform. 3) Rangka kerja elektron membolehkan JavaScript membina aplikasi desktop. 4) Node.js membolehkan JavaScript berjalan di sisi pelayan dan menyokong permintaan serentak yang tinggi.

Python lebih sesuai untuk sains data dan automasi, manakala JavaScript lebih sesuai untuk pembangunan front-end dan penuh. 1. Python berfungsi dengan baik dalam sains data dan pembelajaran mesin, menggunakan perpustakaan seperti numpy dan panda untuk pemprosesan data dan pemodelan. 2. Python adalah ringkas dan cekap dalam automasi dan skrip. 3. JavaScript sangat diperlukan dalam pembangunan front-end dan digunakan untuk membina laman web dinamik dan aplikasi satu halaman. 4. JavaScript memainkan peranan dalam pembangunan back-end melalui Node.js dan menyokong pembangunan stack penuh.

C dan C memainkan peranan penting dalam enjin JavaScript, terutamanya digunakan untuk melaksanakan jurubahasa dan penyusun JIT. 1) C digunakan untuk menghuraikan kod sumber JavaScript dan menghasilkan pokok sintaks abstrak. 2) C bertanggungjawab untuk menjana dan melaksanakan bytecode. 3) C melaksanakan pengkompil JIT, mengoptimumkan dan menyusun kod hot-spot semasa runtime, dan dengan ketara meningkatkan kecekapan pelaksanaan JavaScript.

Aplikasi JavaScript di dunia nyata termasuk pembangunan depan dan back-end. 1) Memaparkan aplikasi front-end dengan membina aplikasi senarai TODO, yang melibatkan operasi DOM dan pemprosesan acara. 2) Membina Restfulapi melalui Node.js dan menyatakan untuk menunjukkan aplikasi back-end.

Penggunaan utama JavaScript dalam pembangunan web termasuk interaksi klien, pengesahan bentuk dan komunikasi tak segerak. 1) kemas kini kandungan dinamik dan interaksi pengguna melalui operasi DOM; 2) pengesahan pelanggan dijalankan sebelum pengguna mengemukakan data untuk meningkatkan pengalaman pengguna; 3) Komunikasi yang tidak bersesuaian dengan pelayan dicapai melalui teknologi Ajax.

Memahami bagaimana enjin JavaScript berfungsi secara dalaman adalah penting kepada pemaju kerana ia membantu menulis kod yang lebih cekap dan memahami kesesakan prestasi dan strategi pengoptimuman. 1) aliran kerja enjin termasuk tiga peringkat: parsing, penyusun dan pelaksanaan; 2) Semasa proses pelaksanaan, enjin akan melakukan pengoptimuman dinamik, seperti cache dalam talian dan kelas tersembunyi; 3) Amalan terbaik termasuk mengelakkan pembolehubah global, mengoptimumkan gelung, menggunakan const dan membiarkan, dan mengelakkan penggunaan penutupan yang berlebihan.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

EditPlus versi Cina retak
Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

SublimeText3 versi Inggeris
Disyorkan: Versi Win, menyokong gesaan kod!

MinGW - GNU Minimalis untuk Windows
Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.