🔍 搜尋結果:vba

🔍 搜尋結果:vba

如何建構:人工智慧驅動的部落格平台(Next.js、Langchain 和 Supabase)

**長話短說** -------- 在本文中,您將學習如何建立一個人工智慧驅動的部落格平台,該平台可以搜尋網路並研究部落格文章的任何主題。 我們將涵蓋: - 用於應用程式框架的 Next.js 🖥️ - 法學碩士 OpenAI 🧠 - LangChain 和 Tavily 的網路搜尋人工智慧代理🤖 - 使用 CopilotKit 將 AI 整合到您的應用程式中 🪁 - Supabase 用於儲存和檢索部落格平台文章資料。 --- CopilotKit:開源 Copilot 框架 ======================== CopilotKit 是[開源 AI 副駕駛框架和平台。](https://github.com/CopilotKit/CopilotKit)我們可以輕鬆地將強大的人工智慧整合到您的 React 應用程式中。 建造: - ChatBots💬:上下文感知的應用內聊天機器人,可以在應用程式內執行操作 - CopilotTextArea📝:人工智慧驅動的文字字段,具有上下文感知自動完成和插入功能 - 聯合代理🤖:應用程式內人工智慧代理,可以與您的應用程式和使用者互動。由浪鏈提供技術支援。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8gltoave8490fg234ro.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} (原諒人工智慧的拼字錯誤並給一顆星:) 現在回到文章。 --- **先決條件** -------- 在開始建立應用程式之前,讓我們先查看建置應用程式所需的依賴項或套件 - `copilotkit/react-core` :CopilotKit 前端包,帶有 React hooks,用於向副駕駛提供應用程式狀態和操作(AI 功能) - `copilotkit/react-ui:`聊天機器人側邊欄 UI 的 CopilotKit 前端包 - `copilotkit/react-textarea:` CopilotKit 前端包,用於在演講者筆記中進行人工智慧輔助文字編輯。 - `LangChainJS:`用於開發由語言模型支援的應用程式的框架。 - `Tavily Search API:`幫助將法學碩士和人工智慧應用程式連接到可信賴的即時知識的 API。 安裝所有專案包和依賴項 ----------- 在安裝所有專案包和依賴項之前,我們首先在終端機上執行以下命令來建立 Nextjs 專案。 ``` npx create-next-app@latest ``` 然後系統會提示您選擇一些選項。請隨意標記它們,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1j04grq2jykx6o606u1s.png) 之後,使用您選擇的文字編輯器開啟新建立的 Nextjs 專案。然後在命令列中執行以下命令來安裝所有專案包和依賴項。 ``` npm i @copilotkit/backend @copilotkit/shared @langchain/langgraph @copilotkit/react-core @copilotkit/react-ui @copilotkit/react-textarea @supabase/ssr @supabase/auth-helpers-nextjs ``` **建立部落格平台前端** ------------- 在本節中,我將引導您完成使用靜態內容建立部落格平台前端的過程,以定義平台的使用者介面。 首先,前往`/[root]/src/app`並建立一個名為`components`的資料夾。在 Components 資料夾中,建立一個名為`Article.tsx`的檔案。 之後,將以下程式碼新增至定義名為`Article`功能元件的檔案中,該元件將用於呈現文章建立表單。 ``` "use client"; import { useRef, useState } from "react"; export function Article() { // Define state variables for article outline, copilot text, and article title const [articleOutline, setArticleOutline] = useState(""); const [copilotText, setCopilotText] = useState(""); const [articleTitle, setArticleTitle] = useState(""); return ( // Form element for article input <form action={""} className="w-full h-full gap-10 flex flex-col items-center p-10"> {/* Input field for article title */} <div className="flex w-full items-start gap-3"> <textarea className="p-2 w-full h-12 rounded-lg flex-grow overflow-x-auto overflow-y-hidden whitespace-nowrap" id="title" name="title" value={articleTitle} placeholder="Article Title" onChange={(event) => setArticleTitle(event.target.value)} /> </div> {/* Textarea for article content */} <textarea className="p-4 w-full aspect-square font-bold text-xl bg-slate-800 text-white rounded-lg resize-none" id="content" name="content" value={copilotText} placeholder="Write your article content here" onChange={(event) => setCopilotText(event.target.value)} /> {/* Publish button */} <button type="submit" className="p-4 w-full !bg-slate-800 text-white rounded-lg">Publish</button> </form> ); } ``` 接下來,將另一個檔案新增到元件資料夾中,並將其命名為`Header.tsx` 。然後將以下程式碼新增至定義名為`Header`的功能元件的檔案中,該元件將呈現部落格平台的導覽列。 ``` import Link from "next/link"; export default function Header() { return ( <> <header className="flex flex-wrap sm:justify-start sm:flex-nowrap z-50 w-full bg-white border-b border-gray-200 text-sm py-3 sm:py-0 "> <nav className="relative max-w-7xl w-full mx-auto px-4 sm:flex sm:items-center sm:justify-between sm:px-6 lg:px-8" aria-label="Global"> <div className="flex items-center justify-between"> <Link className="flex-none text-xl font-semibold " href="/" aria-label="Brand"> AIBlogging </Link> </div> <div id="navbar-collapse-with-animation" className=""> <div className="flex flex-col gap-y-4 gap-x-0 mt-5 sm:flex-row sm:items-center sm:justify-end sm:gap-y-0 sm:gap-x-7 sm:mt-0 sm:ps-7"> <Link className="flex items-center font-medium text-gray-500 border-2 border-indigo-600 text-center p-2 rounded-md hover:text-blue-600 sm:border-s sm:my-6 " href="/writearticle"> Create Post </Link> </div> </div> </nav> </header> </> ); } ``` 之後,轉到`/[root]/src/app`並建立一個名為`writearticle`的資料夾。在`writearticle`資料夾中,建立一個名為`page.tsx`檔案。然後將以下程式碼加入匯入`Article`和`Header`元件的檔案中。然後,程式碼定義了一個名為`WriteArticle`的功能元件,它將呈現導覽列和文章建立表單。 ``` import { Article } from "../components/Article"; import Header from "../components/Header"; export default function WriteArticle() { return ( <> <Header /> <Article /> </> ); } ``` 接下來,前往`/[root]/src/page.tsx`文件,並新增以下程式碼,該程式碼定義一個名為`Home`功能元件,該元件呈現將顯示已發佈文章清單的部落格平台主頁。 ``` import Image from "next/image"; import Link from "next/link"; import Header from "./components/Header"; const Home = async () => { return ( <> <Header /> <div className="max-w-[85rem] h-full px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto"> <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6"> <Link key={""} className="group flex flex-col h-full bg-white border border-gray-200 hover:border-transparent hover:shadow-lg transition-all duration-300 rounded-xl p-5 " href={""}> <div className="aspect-w-16 aspect-h-11"> <Image className="object-cover h-48 w-96 rounded-xl" src={`https://source.unsplash.com/featured/?${encodeURIComponent( "hello world" )}`} width={500} height={500} alt="Image Description" /> </div> <div className="my-6"> <h3 className="text-xl font-semibold text-gray-800 "> Hello World </h3> </div> </Link> </div> </div> </> ); }; export default Home; ``` 之後,請轉到`next.config.js`檔案並加入以下程式碼,該程式碼允許您使用 Unsplash 中的圖像作為已發布文章的封面圖像。 ``` module.exports = { images: { remotePatterns: [ { protocol: "https", hostname: "source.unsplash.com", }, ], }, }; ``` 最後,在命令列上執行命令`npm run dev` ,然後導航到 http://localhost:3000/。現在您應該在瀏覽器上查看部落格平台前端,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m319h0j3ta0xa1fhkezo.png) **將部落格平台與 CopilotKit 後端集成** --------------------------- 在本節中,我將引導您完成將部落格平台與 CopilotKit 後端整合的過程,CopilotKit 後端處理來自前端的請求,提供函數呼叫和各種 LLM 後端(例如 GPT)。此外,我們將整合一個名為 Tavily 的人工智慧代理,它可以研究網路上的任何主題。 首先,在根目錄中建立一個名為`.env.local`的檔案。然後在保存`ChatGPT`和`Tavily` Search API 金鑰的檔案中加入下面的環境變數。 ``` OPENAI_API_KEY="Your ChatGPT API key" TAVILY_API_KEY="Your Tavily Search API key" ``` 若要取得 ChatGPT API 金鑰,請導覽至 https://platform.openai.com/api-keys。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/co9getwdzh34u1k5cehf.png) 若要取得 Tavilly Search API 金鑰,請導覽至 https://app.tavily.com/home ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ju9syhy5w8oip67tyne0.png) 之後,轉到`/[root]/src/app`並建立一個名為`api`的資料夾。在`api`資料夾中,建立一個名為`copilotkit`的資料夾。在`copilotkit`資料夾中,建立一個名為`research.ts`的檔案。然後導航到[該 Research.ts gist 文件](https://gist.github.com/TheGreatBonnie/58dc21ebbeeb8cbb08df665db762738c),複製程式碼,並將其新增至**`research.ts`**檔案中 接下來,在`/[root]/src/app/api/copilotkit`資料夾中建立一個名為`route.ts`的檔案。該文件將包含設定後端功能來處理 POST 請求的程式碼。它有條件地包括對給定主題進行研究的“研究”操作。 現在在文件頂部導入以下模組。 ``` import { CopilotBackend, OpenAIAdapter } from "@copilotkit/backend"; // For backend functionality with CopilotKit. import { researchWithLangGraph } from "./research"; // Import a custom function for conducting research. import { AnnotatedFunction } from "@copilotkit/shared"; // For annotating functions with metadata. ``` 在上面的程式碼下面,定義一個執行時間環境變數和一個名為`researchAction`的函數,該函數使用下面的程式碼對某個主題進行研究。 ``` // Define a runtime environment variable, indicating the environment where the code is expected to run. export const runtime = "edge"; // Define an annotated function for research. This object includes metadata and an implementation for the function. const researchAction: AnnotatedFunction<any> = { name: "research", // Function name. description: "Call this function to conduct research on a certain topic. Respect other notes about when to call this function", // Function description. argumentAnnotations: [ // Annotations for arguments that the function accepts. { name: "topic", // Argument name. type: "string", // Argument type. description: "The topic to research. 5 characters or longer.", // Argument description. required: true, // Indicates that the argument is required. }, ], implementation: async (topic) => { // The actual function implementation. console.log("Researching topic: ", topic); // Log the research topic. return await researchWithLangGraph(topic); // Call the research function and return its result. }, }; ``` 然後在上面的程式碼下加入下面的程式碼來定義處理POST請求的非同步函數。 ``` // Define an asynchronous function that handles POST requests. export async function POST(req: Request): Promise<Response> { const actions: AnnotatedFunction<any>[] = []; // Initialize an array to hold actions. // Check if a specific environment variable is set, indicating access to certain functionality. if (process.env["TAVILY_API_KEY"]) { actions.push(researchAction); // Add the research action to the actions array if the condition is true. } // Instantiate CopilotBackend with the actions defined above. const copilotKit = new CopilotBackend({ actions: actions, }); // Use the CopilotBackend instance to generate a response for the incoming request using an OpenAIAdapter. return copilotKit.response(req, new OpenAIAdapter()); } ``` **將部落格平台與 CopilotKit 前端集成** --------------------------- 在本節中,我將引導您完成將部落格平台與 CopilotKit 前端整合的過程,以促進部落格文章研究和文章大綱生成。我們將使用聊天機器人側欄元件、copilot 文字區域元件、用於向 Copilot 提供應用程式狀態和其他資訊的 useMakeCopilotReadable 掛鉤,以及用於提供 Copilot 可以呼叫的操作的 useCopilotAction 掛鉤 首先,導入`/[root]/src/app/components/Article.tsx`檔案頂部的`useMakeCopilotReadable` 、 `useCopilotAction` 、 `CopilotTextarea`和`HTMLCopilotTextAreaElement`掛鉤。 ``` import { useMakeCopilotReadable, useCopilotAction, } from "@copilotkit/react-core"; import { CopilotTextarea, HTMLCopilotTextAreaElement, } from "@copilotkit/react-textarea"; ``` 在 Article 函數內的狀態變數下方,新增以下程式碼,該程式碼使用`useMakeCopilotReadable`掛鉤來新增將作為應用程式內聊天機器人的上下文產生的文章大綱。鉤子使副駕駛可以閱讀文章大綱。 ``` useMakeCopilotReadable("Blog article outline: " + JSON.stringify(articleOutline)); ``` 在`useMakeCopilotReadable`掛鉤下方,使用以下程式碼建立一個名為`copilotTextareaRef`的引用,該引用指向名為`HTMLCopilotTextAreaElement`的文字區域元素。 ``` const copilotTextareaRef = useRef<HTMLCopilotTextAreaElement>(null); ``` 在上面的程式碼下方,加入以下程式碼,該程式碼使用`useCopilotAction`掛鉤來設定名為`researchBlogArticleTopic`的操作,該操作將啟用對部落格文章的給定主題的研究。此操作採用兩個參數,稱為`articleTitle`和`articleOutline` ,這兩個參數可以產生文章標題和大綱。 該操作包含一個處理程序函數,該函數根據給定主題生成文章標題和大綱。在處理函數內部, `articleOutline`狀態會使用新產生的大綱進行更新,而`articleTitle`狀態會使用新產生的標題進行更新,如下所示。 ``` useCopilotAction( { name: "researchBlogArticleTopic", description: "Research a given topic for a blog article.", parameters: [ { name: "articleTitle", type: "string", description: "Title for a blog article.", required: true, }, { name: "articleOutline", type: "string", description:"Outline for a blog article that shows what the article covers.", required: true, }, ], handler: async ({ articleOutline, articleTitle }) => { setArticleOutline(articleOutline); setArticleTitle(articleTitle); }, }, [] ); ``` 在上面的程式碼下方,前往表單元件並新增以下`CopilotTextarea`元素,該元素將使您能夠為文章內容新增補全、插入和編輯。 ``` <CopilotTextarea value={copilotText} ref={copilotTextareaRef} placeholder="Write your article content here" onChange={(event) => setCopilotText(event.target.value)} className="p-4 w-full aspect-square font-bold text-xl bg-slate-800 text-white rounded-lg resize-none" placeholderStyle={{ color: "white", opacity: 0.5, }} autosuggestionsConfig={{ textareaPurpose: articleTitle, chatApiConfigs: { suggestionsApiConfig: { forwardedParams: { max_tokens: 5, stop: ["\n", ".", ","], }, }, insertionApiConfig: {}, }, debounceTime: 250, }} /> ``` 然後將Tailwindcss隱藏類別加入文章內容的Textarea中,如下所示。文字區域將保存文章的內容,並在文章發布後將其插入資料庫。 ``` {/* Textarea for article content */} <textarea className="p-4 w-full aspect-square font-bold text-xl bg-slate-800 text-white rounded-lg resize-none hidden" id="content" name="content" value={copilotText} placeholder="Write your article content here" onChange={(event) => setCopilotText(event.target.value)} /> ``` 之後,請前往`/[root]/src/app/writearticle/page.tsx`檔案並使用下面的程式碼匯入頂部的 CopilotKit 前端套件和樣式。 ``` import { CopilotKit } from "@copilotkit/react-core"; import { CopilotSidebar } from "@copilotkit/react-ui"; import "@copilotkit/react-ui/styles.css"; import "@copilotkit/react-textarea/styles.css"; ``` 然後使用`CopilotKit`和`CopilotSidebar`包裹Article元件,如下所示。 `CopilotKit`元件指定 CopilotKit 後端端點 ( `/api/copilotkit/openai/` ) 的 URL,而`CopilotSidebar`則呈現應用程式內聊天機器人,您可以提示您研究文章的任何主題。 ``` export default function WriteArticle() { return ( <> <Header /> <CopilotKit url="/api/copilotkit"> <CopilotSidebar instructions="Help the user research a blog article topic." defaultOpen={true} labels={{ title: "Blog Article Copilot", initial: "Hi you! 👋 I can help you research any topic for a blog article.", }} clickOutsideToClose={false}> <Article /> </CopilotSidebar> </CopilotKit> </> ); } ``` 之後,執行開發伺服器並導航到 http://localhost:3000/writearticle。您應該會看到應用程式內聊天機器人已整合到部落格平台中。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yx7m6fhxm9gdg942a0sq.png) 給右側的聊天機器人一個提示,例如“研究一篇關於生成人工智慧的部落格文章主題,然後給我文章大綱。”聊天機器人將開始研究該主題,然後產生部落格標題。 當您開始在編輯器上寫作時,您應該會看到內容自動建議,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocnhptqxnk5gopvlzfs8.png) **將部落格平台與 Supabase 資料庫集成** -------------------------- 在本節中,我將引導您完成將部落格平台與 Supabase 資料庫整合以插入和獲取部落格文章資料的過程。 首先,導覽至[supabase.com](http://supabase.com)並點擊主頁上的「啟動您的專案」按鈕。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95n06a6aj55r5w959gz6.png) 然後新建一個專案,名為AiBloggingPlatform,如下圖所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lifhztowgy3g1v9wwnjk.png) 建立專案後,將 Supabase URL 和 API 金鑰新增至 env.local 檔案中的環境變數中,如下所示。 ``` NEXT_PUBLIC_SUPABASE_URL=”Your Supabase URL” NEXT_PUBLIC_SUPABASE_ANON_KEY=”Your Supabase API Key” ``` 之後,請前往 Supabase 上專案的儀表板並開啟 SQL 編輯器部分。然後將下列 SQL 程式碼新增至編輯器中,然後按一下 CTRL + Enter 鍵建立一個名為articles 的表。文章表包含 id、標題和內容行。 ``` create table if not exists articles ( id bigint primary key generated always as identity, title text, content text ); ``` 建立表格後,您應該會收到一條成功訊息,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjb84czwivk6ue7duj0b.png) 之後,轉到`/[root]/src/`資料夾並建立一個名為`utils`的資料夾。在`utils`資料夾內,建立一個名為`supabase.ts`文件,並新增以下用於建立並傳回 Supabase 用戶端的程式碼。 ``` // Importing necessary functions and types from the Supabase SSR package import { createServerClient, type CookieOptions } from '@supabase/ssr' // Define a function named 'supabase' that takes a 'CookieOptions' object as input export const supabase = (cookies: CookieOptions) => { // Retrieve cookies from the provided 'CookieOptions' object const cookieStore = cookies() // Create and return a Supabase client configured with environment variables and cookie handling return createServerClient( // Retrieve Supabase URL from environment variables process.env.NEXT_PUBLIC_SUPABASE_URL!, // Retrieve Supabase anonymous key from environment variables process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { // Define a custom 'get' function to retrieve cookies by name from the cookie store get(name: string) { return cookieStore.get(name)?.value }, }, } ) } ``` 然後轉到`/[root]/src/app`資料夾並建立一個名為`serveractions`的資料夾。在`serveractions`資料夾中,建立一個名為`AddArticle.ts`的文件,並新增以下程式碼,將部落格文章資料插入到 Supabase 資料庫中。 ``` // Importing necessary functions and modules for server-side operations "use server"; import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; // Define an asynchronous function named 'addArticle' that takes form data as input export async function addArticle(formData: any) { // Extract title and content from the provided form data const title = formData.get("title"); const content = formData.get("content"); // Retrieve cookies from the HTTP headers const cookieStore = cookies(); // Create a Supabase client configured with the provided cookies const supabase = createServerComponentClient({ cookies: () => cookieStore }); // Insert the article data into the 'articles' table on Supabase const { data, error } = await supabase.from("articles").insert([ { title, content, }, ]); // Check for errors during the insertion process if (error) { console.error("Error inserting data", error); return; } // Redirect the user to the home page after successfully adding the article redirect("/"); // Return a success message return { message: "Success" }; } ``` 之後,轉到`/[root]/src/app/components/Article.tsx`檔案並導入`addArticle`函數。 ``` import { addArticle } from "../serveractions/AddArticle"; ``` 然後加入`addArticle`函數作為表單動作參數,如下所示。 ``` // Form element for article input <form action={addArticle} className="w-full h-full gap-10 flex flex-col items-center p-10"> </form> ``` 之後,導覽至http://localhost:3000/writearticle,研究您選擇的主題,新增文章內容,然後點擊底部的發布按鈕來發布文章。 然後轉到 Supabase 上專案的儀表板並導航到表編輯器部分。您應該會看到您的文章資料已插入 Supabase 資料庫,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fklcuyv5q5eq1ajmdjyv.png) 接下來,前往`/[root]/src/app/page.tsx`檔案並在頂部導入 cookie 和 supabase 套件。 ``` import { cookies } from "next/headers"; import { supabase } from "@/utils/supabase"; ``` 然後在 Home 函數中加入以下程式碼,從 Supabase 資料庫中取得文章資料。 ``` const { data: articles, error } = await supabase(cookies).from('articles').select('*') ``` 之後,更新如下所示的元素程式碼,以將已發佈的文章呈現在部落格平台主頁上。 ``` return ( <> <Header /> <div className="max-w-[85rem] h-full px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto"> <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6"> {articles?.map((post: any) => ( <Link key={post.id} className="group flex flex-col h-full bg-white border border-gray-200 hover:border-transparent hover:shadow-lg transition-all duration-300 rounded-xl p-5 " href={`/posts/${post.id}`}> <div className="aspect-w-16 aspect-h-11"> <Image className="object-cover h-48 w-96 rounded-xl" src={`https://source.unsplash.com/featured/?${encodeURIComponent( post.title )}`} width={500} height={500} alt="Image Description" /> </div> <div className="my-6"> <h3 className="text-xl font-semibold text-gray-800 "> {post.title} </h3> </div> </Link> ))} </div> </div> </> ); ``` 然後導航到[http://localhost:3000](http://localhost:3000/writearticle) ,您應該會看到您發布的文章,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/429bilwyje2a4xh0il5n.png) 之後,轉到`/[root]/src/app`資料夾並建立一個名為`[id].`在`[id]`資料夾中,建立一個名為`page.tsx`的文件,並在頂部匯入以下套件和元件。 ``` import { supabase } from '@/utils/supabase'; import { cookies } from "next/headers"; import Header from '@/app/components/Header'; ``` 在導入下面,定義一個名為「getArticles」的非同步函數,該函數根據 id 參數從 supabase 資料庫檢索文章資料,如下所示。 ``` // Define an asynchronous function named 'getArticles' that retrieves article data based on the provided parameters async function getArticles(params: any) { // Extract the 'id' parameter from the provided 'params' object const { id } = params // Retrieve article data from Supabase database where the 'id' matches the provided value const { data, error } = await supabase(cookies) .from('articles') .select('*') .eq('id', id) .single(); // Return the retrieved data return data } ``` 在上面的程式碼下面,定義一個名為“Post”的函數,它將“params”作為 props,如下所示。 ``` // Define a default asynchronous function named 'Post' that takes 'params' as props export default async function Post({ params }: { params: any }) { // Retrieve the post data asynchronously based on the provided 'params' const post = await getArticles(params); // Return JSX to render the post details return ( <> {/* Render the header component */} <Header /> {/* Main content wrapper */} <div className="max-w-3xl px-4 pt-6 lg:pt-10 pb-12 sm:px-6 lg:px-8 mx-auto"> <div className="max-w-2xl"> <div className="space-y-5 md:space-y-8"> <div className="space-y-3"> {/* Render the post title */} <h2 className="text-2xl font-bold md:text-3xl dark:text-white"> {/* Render the post title only if 'post' is truthy */} {post && post.title} </h2> {/* Render the post content */} <p className="text-lg text-gray-800 dark:text-gray-200"> {/* Render the post content only if 'post' is truthy */} {post && post.content} </p> </div> </div> </div> </div> </> ); } ``` 之後,導覽至[http://localhost:3000](http://localhost:3000/writearticle)並點擊部落格平台主頁上顯示的文章。 然後您應該被重定向到文章的內容,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojie4iwb8qn56gd2a907.png) 結論 -- 總而言之,您可以使用 CopilotKit 建立應用內 AI 聊天機器人,該機器人可以查看當前應用程式狀態並在應用程式內執行操作。 AI 聊天機器人可以與您的應用程式前端、後端和第三方服務對話。 完整的原始碼:https://github.com/TheGreatBonnie/aipoweredblog --- 原文出處:https://dev.to/copilotkit/how-to-build-an-ai-powered-blogging-platform-nextjs-langchain-supabase-1hdp

在 React 中編寫乾淨、可重複使用的元件(最佳實踐)

🔑 關鍵概念 ------ 什麼是可重複使用的 React 元件?您可以將它們視為建置塊。 它們是獨立的程式碼片段,可以在整個網站中重複使用,以節省您的時間和精力。 它們可以是從簡單按鈕到複雜表單的任何內容。 **為什麼要使用可重複使用的元件?** 隨著您的網站的發展,您可以透過組合現有元件輕鬆加入新功能。這使您的程式碼更具可擴展性和適應性。 您可以**在未來的專案中使用可重複使用的程式碼,**而無需從頭開始重新編寫。 --- 🧩 如何寫出乾淨、可重複使用的 React 元件 ------------------------ 在編寫乾淨的可重複使用 React 元件時,需要記住以下*兩個最重要的*事情: ![React 可重複使用元件的圖像](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yuprsf67nntkgexmo92w.jpg) **1. 🩼避免副作用。**不要將與外部資料互動的邏輯(例如進行 API 呼叫)直接放入可重複使用元件中。相反,將此邏輯作為`props`傳遞給元件。 例如,如果一個按鈕不僅僅是看起來漂亮,例如從網路獲取資料,**那麼它可能無法重複使用。** 在您掌握透過最佳實踐傳遞 props 的概念之前,我不會向您展示這方面的範例。繼續閱讀。 這是一個可重複使用的按鈕元件。但它缺乏最佳實踐。我將在範例部分向您展示原因。 ``` // This is a reusable button component (bad practice!) const Button = () => { return ( <button> Click Me </button> ); } ``` ‍ **2. 🗃️使用 props。** Props 是傳遞給元件以自訂其行為和外觀的參數。這允許您將相同的元件用於不同的目的。 ``` // This is a button component that can change its color const Button = ({ color }) => { return ( <button style={{ backgroundColor: color }}> Click Here </button> ); } ``` 這仍然是一個不好的做法,因為您有一個名為「點擊這裡」的固定標籤。如果您想更改按鈕上的文本,例如“註冊”,那麼您必須返回按鈕元件並進行更改。 這意味著每次我們想要使用不同的文字時,我們都必須返回並編輯程式碼。換句話說,它不再可重複使用。 **💪 挑戰:**那麼解決方案是什麼? 你已經有了答案。但如果您不這樣做,我將在範例部分向您展示。 **🌴提示:**考慮一下您可能希望如何在不同情況下使用該元件,並將其設計得靈活且適應性強。 🍃可重複使用 React 元件的範例 ------------------ 以下是可重複使用 React 元件的一些常見範例,以及一些幫助您入門的程式碼範例: **1. 按鈕:**具有不同樣式和功能的基本按鈕。 ``` // Button component import React from "react"; const Button = ({ color, label, onClick }) => { return ( <button className={`padding-2 shadow-none hover:shadow background-light-${color} hover:background-dark-${color}`} onClick={onClick} > {label} </button> ); }; export default Button; // Using the Button component <Button color="blue" label="Click Here" onClick={() => console.log("Button clicked!")} /> ``` 正如你所看到的,我沒有在按鈕元件中寫“Click Here”。我想讓我的按鈕可重複使用,因此它不知道有關自訂樣式或文字的任何資訊。 因此,我將它們作為 props(例如,顏色、標籤、onClick)傳遞,以便將來更改它們,而無需觸摸原始按鈕元件。希望這能說清楚。 > **🪜解決方案:**您需要將每個功能作為可重複使用元件中的`props`傳遞 - 就是這樣。 **2. 導覽列:**在整個網站上提供一致導覽的導覽列。 ``` // Navbar component import React from "react"; const Navbar = ({ isLoggedIn }) => { return ( <div className="navbar"> <div className="navbar-container"> <div className="navbar-logo"> <img src={logo} alt="logo" /> </div> <div className="navbar-links"> <a href="/">Home</a> <a href="/about">About</a> <a href="/contact">Contact</a> {isLoggedIn ? ( <a href="/profile">Profile</a> ) : ( <a href="/login">Login</a> )} </div> </div> </div> ); }; export default Navbar; // Using the Navbar component <Navbar isLoggedIn={true} /> ``` 如您所見,我通過了`<Navbar isLoggedIn={true} />` 此行利用`Navbar`元件並傳遞值為 true 的`isLoggedIn`屬性,表示使用者已登入。這將顯示「個人資料」連結並隱藏「登入」連結。 與按鈕元件類似,導覽列元件是可重複使用的,並接受 props 來自訂其行為。完美的! **3. 為什麼在按鈕元件中呼叫 API 是不好的做法** 現在,您已經了解了 React 中可重複使用元件的所有內容。 讓我們透過解決一個複雜的問題來更深入地研究。 考慮這樣的場景,您有一個執行 API 呼叫的按鈕。按鈕元件的程式碼可以如下: ``` import React from "react"; import doAPICall from "../api" const SaveButton = () => { return ( <button onClick={() => { doAPICall(); }} > Save </button> ); } export default SaveButton ``` 很明顯,您不能在多個地方重複使用上述按鈕,因為該按鈕元件內部包含副作用( `doAPICall()` )。 為了使該元件可重複使用,首先,您必須提取副作用並將其作為 prop 傳遞給按鈕元件,如下所示: ``` const App = () => { function doAPICall() { // Does an API call to save the current state of the app. } return ( <div> <SaveButton onClick={doAPICall}/> </div> ) } ``` 按鈕元件將如下所示: ``` const SaveButton = ({ onClick }) => { return ( <button onClick={onClick} > Save </button> ); } ``` 正如您所看到的,現在可以在您想要透過點擊按鈕儲存資料的所有位置重複使用上面的按鈕。該按鈕現在可以在多個地方像這樣使用: ``` const App = () => { function saveUser() { // Does an API call to save the user. } function saveProject() { // Does an API call to save the project. } return ( <div> <SaveButton onClick={saveUser}/> <SaveButton onClick={saveProject}/> </div> ) } ``` 您也可以透過使用 prop 來控制標籤,使按鈕元件更具可重複使用性,如下所示: ``` const App = () => { function saveUser() { // Does an API call to save the user. } function saveProject() { // Does an API call to save the project. } return ( <div> <SaveButton onClick={saveUser} label="Save user" /> <SaveButton onClick={saveProject} label="Save project" /> </div> ) } ``` 按鈕元件將如下所示: ``` const SaveButton = ({ onClick, label }) => { return ( <button onClick={onClick} > {label} </button> ); } ``` **🫧 推薦:🤖🦾 [Figma AI:](https://psxid.figma.com/8g4g75niz3sg-7v0ro9)** 如果您需要快速設計簡報或網站,Figma AI 可以提供現成的範本。並且它可以與[Figma](https://psxid.figma.com/pq1612tcamkx)順利配合。只要告訴它你想要什麼,畫一點,然後繁榮——你的想法就變成現實了! ![Figma AI 影像](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cj5cxhykwmfnmve77co.png) 您可以嘗試[Figma AI](https://psxid.figma.com/8g4g75niz3sg-7v0ro9) ,目前它對所有人免費。 --- 👏結論 --- 恭喜!您已經成功學習如何使用最佳實踐建立乾淨的可重複使用 React 元件。 請記住,**可重複使用元件是健壯的 React 開發的建置塊**。透過練習可重複使用元件,您可以建立更乾淨、更有效率、更易於維護的 React 應用程式。 您練習得越多,您就越能更好地辨識在專案中使用它們的機會! 如果您喜歡這篇文章,您可能也會喜歡我的[𝕏](https://twitter.com/shahancd)帳戶,以了解更多有關前端開發的課程。 **閱讀更多:**[前端開發的未來](https://dev.to/codewithshahan/the-future-of-frontend-development-1amd) --- 原文出處:https://dev.to/codewithshahan/writing-clean-reusable-components-in-react-best-practices-2gka

我正在建立一個全端應用程式:以下是我將要使用的庫......

您可以使用無數的框架和函式庫來改進您的全端應用程式。 我們將介紹令人興奮的概念,例如應用程式內通知、使用 React 製作影片、從為開發人員提供的電子郵件 API 到在瀏覽器中建立互動式音樂。 那我們就開始吧。 (不要忘記為這些庫加註星標以表示您的支持)。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qqoipyuoxgb83swyoo4a.gif) https://github.com/CopilotKit/CopilotKit --- 1. [CopilotKit](https://github.com/CopilotKit/CopilotKit) - 在數小時內為您的產品提供 AI Copilot。 ------------------------------------------------------------------------------------ ![副駕駛套件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzuxjfog2ldam3csrl62.png) 您可以使用兩個 React 元件將關鍵 AI 功能整合到 React 應用程式中。它們還提供內建(完全可自訂)Copilot 原生 UX 元件,例如`<CopilotKit />` 、 `<CopilotPopup />` 、 `<CopilotSidebar />` 、 `<CopilotTextarea />` 。 開始使用以下 npm 指令。 ``` npm i @copilotkit/react-core @copilotkit/react-ui @copilotkit/react-textarea ``` 這是整合 CopilotTextArea 的方法。 ``` import { CopilotTextarea } from "@copilotkit/react-textarea"; import { useState } from "react"; export function SomeReactComponent() { const [text, setText] = useState(""); return ( <> <CopilotTextarea className="px-4 py-4" value={text} onValueChange={(value: string) => setText(value)} placeholder="What are your plans for your vacation?" autosuggestionsConfig={{ textareaPurpose: "Travel notes from the user's previous vacations. Likely written in a colloquial style, but adjust as needed.", chatApiConfigs: { suggestionsApiConfig: { forwardedParams: { max_tokens: 20, stop: [".", "?", "!"], }, }, }, }} /> </> ); } ``` 您可以閱讀[文件](https://docs.copilotkit.ai/getting-started/quickstart-textarea)。 基本概念是在幾分鐘內建立可用於基於 LLM 的全端應用程式的 AI 聊天機器人。 https://github.com/CopilotKit/CopilotKit --- 2. [Storybook](https://github.com/storybookjs/storybook) - UI 開發、測試和文件變得簡單。 --------------------------------------------------------------------------- ![故事書](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78rfum1ydisn51qhb408.png) Storybook 是一個用於獨立建立 UI 元件和頁面的前端工作坊。它有助於 UI 開發、測試和文件編制。 他們在 GitHub 上有超過 57,000 次提交、81,000 多個 star 和 1300 多個版本。 這是您為專案建立簡單元件的方法。 ``` import type { Meta, StoryObj } from '@storybook/react'; import { YourComponent } from './YourComponent'; //👇 This default export determines where your story goes in the story list const meta: Meta<typeof YourComponent> = { component: YourComponent, }; export default meta; type Story = StoryObj<typeof YourComponent>; export const FirstStory: Story = { args: { //👇 The args you need here will depend on your component }, }; ``` 您可以閱讀[文件](https://storybook.js.org/docs/get-started/setup)。 如今,UI 除錯起來很痛苦,因為它們與業務邏輯、互動狀態和應用程式上下文糾纏在一起。 Storybook 提供了一個獨立的 iframe 來渲染元件,而不會受到應用程式業務邏輯和上下文的干擾。這可以幫助您將開發重點放在元件的每個變體上,甚至是難以觸及的邊緣情況。 https://github.com/storybookjs/storybook --- 3. [Appwrite](https://github.com/appwrite/appwrite) - 您的後端減少麻煩。 --------------------------------------------------------------- ![應用程式寫入](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8x568uz21seyygw6b72z.png) ![帶有 appwrite 的 sdk 列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp7k8qnamsluto7eifpl.png) Appwrite 的開源平台可讓您將身份驗證、資料庫、函數和儲存體新增至您的產品中,並建立任何規模的任何應用程式、擁有您的資料並使用您喜歡的編碼語言和工具。 他們有很好的貢獻指南,甚至不厭其煩地詳細解釋架構。 開始使用以下 npm 指令。 ``` npm install appwrite ``` 您可以像這樣建立一個登入元件。 ``` "use client"; import { useState } from "react"; import { account, ID } from "./appwrite"; const LoginPage = () => { const [loggedInUser, setLoggedInUser] = useState(null); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [name, setName] = useState(""); const login = async (email, password) => { const session = await account.createEmailSession(email, password); setLoggedInUser(await account.get()); }; const register = async () => { await account.create(ID.unique(), email, password, name); login(email, password); }; const logout = async () => { await account.deleteSession("current"); setLoggedInUser(null); }; if (loggedInUser) { return ( <div> <p>Logged in as {loggedInUser.name}</p> <button type="button" onClick={logout}> Logout </button> </div> ); } return ( <div> <p>Not logged in</p> <form> <input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} /> <input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} /> <input type="text" placeholder="Name" value={name} onChange={(e) => setName(e.target.value)} /> <button type="button" onClick={() => login(email, password)}> Login </button> <button type="button" onClick={register}> Register </button> </form> </div> ); }; export default LoginPage; ``` 您可以閱讀[文件](https://appwrite.io/docs)。 Appwrite 可以非常輕鬆地建立具有開箱即用的擴充功能的可擴展後端應用程式。 https://github.com/appwrite/appwrite --- 4. [Wasp](https://github.com/wasp-lang/wasp) - 用於 React、node.js 和 prisma 的類似 Rails 的框架。 --------------------------------------------------------------------------------------- ![黃蜂](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi2mwazueoc3ezjx8a9q.png) 使用 React 和 Node.js 開發全端 Web 應用程式的最快方法。這不是一個想法,而是一種建立瘋狂快速全端應用程式的不同方法。 這是將其整合到元件中的方法。 ``` import getRecipes from "@wasp/queries/getRecipes"; import { useQuery } from "@wasp/queries"; import type { User } from "@wasp/entities"; export function HomePage({ user }: { user: User }) { // Due to full-stack type safety, `recipes` will be of type `Recipe[]` here. const { data: recipes, isLoading } = useQuery(getRecipes); // Calling our query here! if (isLoading) { return <div>Loading...</div>; } return ( <div> <h1>Recipes</h1> <ul> {recipes ? recipes.map((recipe) => ( <li key={recipe.id}> <div>{recipe.title}</div> <div>{recipe.description}</div> </li> )) : 'No recipes defined yet!'} </ul> </div> ); } ``` 您可以閱讀[文件](https://wasp-lang.dev/docs)。 https://github.com/wasp-lang/wasp --- 5. [Novu](https://github.com/novuhq/novu) - 將應用程式內通知新增至您的應用程式! -------------------------------------------------------------- ![再次](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/716b7biilet4auudjlcu.png) Novu 提供開源通知基礎架構和功能齊全的嵌入式通知中心。 這就是如何使用`React`建立 novu 元件以用於應用程式內通知。 ``` import { NovuProvider, PopoverNotificationCenter, NotificationBell, } from "@novu/notification-center"; function App() { return ( <> <NovuProvider subscriberId={process.env.REACT_APP_SUB_ID} applicationIdentifier={process.env.REACT_APP_APP_ID} > <PopoverNotificationCenter> {({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />} </PopoverNotificationCenter> </NovuProvider> </> ); } export default App; ``` 您可以閱讀[文件](https://docs.novu.co/getting-started/introduction)。 https://github.com/novuhq/novu --- 6. [Remotion](https://github.com/remotion-dev/remotion) - 使用 React 以程式設計方式製作影片。 ------------------------------------------------------------------------------- ![遠端](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmnrxhsc7b9mm5oagflm.png) 使用 React 建立真正的 MP4 影片,使用伺服器端渲染和參數化擴展影片製作。 開始使用以下 npm 指令。 ``` npm init video ``` 它為您提供了一個幀號和一個空白畫布,您可以在其中使用 React 渲染任何您想要的內容。 這是一個範例 React 元件,它將當前幀渲染為文字。 ``` import { AbsoluteFill, useCurrentFrame } from "remotion";   export const MyComposition = () => { const frame = useCurrentFrame();   return ( <AbsoluteFill style={{ justifyContent: "center", alignItems: "center", fontSize: 100, backgroundColor: "white", }} > The current frame is {frame}. </AbsoluteFill> ); }; ``` 您可以閱讀[文件](https://www.remotion.dev/docs/)。 過去兩年,remotion 團隊因製作 GitHub Wrapped 而聞名。 https://github.com/remotion-dev/remotion --- [7.NocoDB](https://github.com/nocodb/nocodb) - Airtable 的替代品。 ------------------------------------------------------------- ![諾科資料庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iw3tchfgyzehye5c39xq.png) Airtable 的免費開源替代品是 NocoDB。它可以使用任何 MySQL、PostgreSQL、SQL Server、SQLite 或 MariaDB 資料庫製作智慧型電子表格。 其主要目標是讓強大的計算工具得到更廣泛的使用。 開始使用以下 npx 指令。 ``` npx create-nocodb-app ``` 您可以閱讀[文件](https://docs.nocodb.com/)。 NocoDB 的建立是為了為世界各地的數位企業提供強大的開源和無程式碼資料庫介面。 您可以非常快速地將airtable資料匯入NocoDB。 https://github.com/nocodb/nocodb --- 8.[新穎](https://github.com/steven-tey/novel)- 所見即所得編輯器,具有人工智慧自動完成功能。 ------------------------------------------------------------------- ![小說](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uo34vd9twpxcpbpzgchi.png) 它使用`Next.js` 、 `Vercel AI SDK` 、 `Tiptap`作為文字編輯器。 開始使用以下 npm 指令。 ``` npm i novel ``` 您可以這樣使用它。有多種選項可用於改進您的應用程式。 ``` import { Editor } from "novel"; export default function App() { return <Editor />; } ``` https://github.com/steven-tey/novel --- 9. [Blitz](https://github.com/blitz-js/blitz) - 缺少 NextJS 的全端工具包。 ----------------------------------------------------------------- ![閃電戰](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vz6ineg1o7xyv7pwbuqn.png) Blitz 繼承了 Next.js 的不足,為全球應用程式的交付和擴展提供了經過實戰考驗的函式庫和約定。 開始使用以下 npm 指令。 ``` npm install -g blitz ``` 這就是您如何使用 Blitz 建立新頁面。 ``` const NewProjectPage: BlitzPage = () => { const router = useRouter() const [createProjectMutation] = useMutation(createProject) return ( <div> <h1>Create New Project</h1> <ProjectForm submitText="Create Project" schema={CreateProject} onSubmit={async (values) => { // This is equivalent to calling the server function directly const project = await createProjectMutation(values) // Notice the 'Routes' object Blitz provides for routing router.push(Routes.ProjectsPage({ projectId: project.id })) }} /> </div> ); }; NewProjectPage.authenticate = true NewProjectPage.getLayout = (page) => <Layout>{page}</Layout> export default NewProjectPage ``` 您可以閱讀[文件](https://blitzjs.com/docs/get-started)。 它使建築物改善了數倍。 ![閃電戰](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc4mb5wdksjv1ybx71co.png) https://github.com/blitz-js/blitz --- 10. [Supabase](https://github.com/supabase/supabase) - 開源 Firebase 替代品。 ----------------------------------------------------------------------- ![蘇帕貝斯](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ksfygjhrzhmsg9cnvobs.png) 我們大多數人都已經預料到 SUPABASE 會出現在這裡,因為它實在是太棒了。 開始使用以下 npm 指令 (Next.js)。 ``` npx create-next-app -e with-supabase ``` 這是使用 supabase 建立用戶的方法。 ``` import { createClient } from '@supabase/supabase-js' // Initialize const supabaseUrl = 'https://chat-room.supabase.co' const supabaseKey = 'public-anon-key' const supabase = createClient(supabaseUrl, supabaseKey) // Create a new user const { user, error } = await supabase.auth.signUp({ email: '[email protected]', password: 'example-password', }) ``` 您可以閱讀[文件](https://supabase.com/docs)。 您可以使用身份驗證、即時、邊緣功能、儲存等功能建立一個速度極快的應用程式。 Supabase 涵蓋了這一切! 他們還提供了一些入門套件,例如 AI 聊天機器人和 Stripe 訂閱。 https://github.com/supabase/supabase --- [11.Refine](https://github.com/refinedev/refine) - 企業開源重組工具。 ------------------------------------------------------------ ![精煉](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qx0kd6t2jzdtf90k5ke3.png) 建立具有無與倫比的靈活性的管理面板、儀表板和 B2B 應用程式 您可以在一分鐘內使用單一 CLI 命令進行設定。 它具有適用於 15 多個後端服務的連接器,包括 Hasura、Appwrite 等。 開始使用以下 npm 指令。 ``` npm create refine-app@latest ``` 這就是使用 Refine 新增登入資訊的簡單方法。 ``` import { useLogin } from "@refinedev/core"; const { login } = useLogin(); ``` 您可以閱讀[文件](https://refine.dev/docs/)。 https://github.com/refinedev/refine --- 12. [Zenstack](https://github.com/zenstackhq/zenstack) - 資料庫到 API 和 UI 只需幾分鐘。 ----------------------------------------------------------------------------- ![禪斯塔克](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3b6n2ea3jeeva6uujoex.png) TypeScript 工具包,透過強大的存取控制層增強 Prisma ORM,並釋放其全端開發的全部功能。 開始使用以下 npx 指令。 ``` npx zenstack@latest init ``` 這是透過伺服器適配器建立 RESTful API 的方法。 ``` // pages/api/model/[...path].ts import { requestHandler } from '@zenstackhq/next'; import { enhance } from '@zenstackhq/runtime'; import { getSessionUser } from '@lib/auth'; import { prisma } from '@lib/db'; // Mount Prisma-style APIs: "/api/model/post/findMany", "/api/model/post/create", etc. // Can be configured to provide standard RESTful APIs (using JSON:API) instead. export default requestHandler({ getPrisma: (req, res) => enhance(prisma, { user: getSessionUser(req, res) }), }); ``` 您可以閱讀[文件](https://zenstack.dev/docs/welcome)。 https://github.com/zenstackhq/zenstack --- 13. [Buildship](https://github.com/rowyio/buildship) - 低程式碼視覺化後端建構器。 -------------------------------------------------------------------- ![建造船](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzlrynz5xephv4t9layd.png) 對於您正在使用無程式碼應用程式建構器(FlutterFlow、Webflow、Framer、Adalo、Bubble、BravoStudio...)或前端框架(Next.js、React、Vue...)建立的應用程式,您需要一個後端來支援可擴展的 API、安全工作流程、自動化等。BuildShip 為您提供了一種完全視覺化的方式,可以在易於使用的完全託管體驗中可擴展地建立這些後端任務。 這意味著您不需要在雲端平台上爭論或部署東西、執行 DevOps 等。只需立即建置和交付 🚀 https://github.com/rowyio/buildship --- 14. [Taipy](https://github.com/Avaiga/taipy) - 將資料和人工智慧演算法整合到生產就緒的 Web 應用程式中。 ----------------------------------------------------------------------------- ![打字](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohv3johuz92lsaux52oq.png) Taipy 是一個開源 Python 庫,用於輕鬆的端到端應用程式開發, 具有假設分析、智慧管道執行、內建調度和部署工具。 開始使用以下命令。 ``` pip install taipy ``` 這是一個典型的Python函數,也是過濾器場景中使用的唯一任務。 ``` def filter_genre(initial_dataset: pd.DataFrame, selected_genre): filtered_dataset = initial_dataset[initial_dataset['genres'].str.contains(selected_genre)] filtered_data = filtered_dataset.nlargest(7, 'Popularity %') return filtered_data ``` 您可以閱讀[文件](https://docs.taipy.io/en/latest/)。 他們還有很多可供您建立的[演示應用程式教學](https://docs.taipy.io/en/latest/knowledge_base/demos/)。 https://github.com/Avaiga/taipy --- 15. [LocalForage](https://github.com/localForage/localForage) - 改進了離線儲存。 ------------------------------------------------------------------------ ![當地飼料](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hlrka5pybvmgmo2djel.png) LocalForage 是一個 JavaScript 函式庫,它透過使用非同步資料儲存和簡單的、類似 localStorage 的 API 來改善 Web 應用程式的離線體驗。它允許開發人員儲存多種類型的資料而不僅僅是字串。 開始使用以下 npm 指令。 ``` npm install localforage ``` 只需包含 JS 檔案並開始使用 localForage。 ``` <script src="localforage.js"></script> ``` 您可以閱讀[文件](https://localforage.github.io/localForage/#installation)。 https://github.com/localForage/localForage --- 16. [Zod](https://github.com/colinhacks/zod) - 使用靜態類型推斷的 TypeScript-first 模式驗證。 ------------------------------------------------------------------------------- ![佐德](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1s6zvmqr0lv93vsrhofs.png) Zod 的目標是透過最大限度地減少重複的類型聲明來對開發人員友好。使用 Zod,您聲明一次驗證器,Zod 將自動推斷靜態 TypeScript 類型。將更簡單的類型組合成複雜的資料結構很容易。 開始使用以下 npm 指令。 ``` npm install zod ``` 這是您在建立字串架構時自訂一些常見錯誤訊息的方法。 ``` const name = z.string({ required_error: "Name is required", invalid_type_error: "Name must be a string", }); ``` 您可以閱讀[文件](https://zod.dev/)。 它適用於 Node.js 和所有現代瀏覽器 https://github.com/colinhacks/zod --- 17.[多普勒](https://github.com/DopplerHQ)- 管理你的秘密。 ----------------------------------------------- ![多普勒](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gycxnuiiwsvibryrytlc.png) 您可以透過在具有開發、暫存和生產環境的專案中組織機密來消除機密蔓延。 開始使用以下指令 (MacOS)。 ``` $ brew install dopplerhq/cli/doppler $ doppler --version ``` 這是安裝 Doppler CLI[的 GitHub Actions 工作流程](https://github.com/DopplerHQ/cli-action)。 您可以閱讀[文件](https://docs.doppler.com/docs/start)。 ``` name: Example action on: [push] jobs: my-job: runs-on: ubuntu-latest steps: - name: Install CLI uses: dopplerhq/cli-action@v3 - name: Do something with the CLI run: doppler secrets --only-names env: DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }} ``` https://github.com/DopplerHQ --- 18. [FastAPI](https://github.com/tiangolo/fastapi) - 高效能、易於學習、快速編碼、可用於生產。 ------------------------------------------------------------------------- ![快速API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2awncoia6255ycl95lk.png) FastAPI 是一個現代、快速(高效能)的 Web 框架,用於基於標準 Python 類型提示使用 Python 3.8+ 建立 API。 開始使用以下命令。 ``` $ pip install fastapi ``` 這是您開始使用 FastAPI 的方式。 ``` from typing import Union from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"Hello": "World"} @app.get("/items/{item_id}") def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` 您的編輯器將自動完成屬性並了解它們的類型,這是使用 FastAPI 的最佳功能之一。 您可以閱讀[文件](https://fastapi.tiangolo.com/)。 https://github.com/tiangolo/fastapi --- 19. [Flowise](https://github.com/FlowiseAI/Flowise) - 拖放 UI 來建立您的客製化 LLM 流程。 ---------------------------------------------------------------------------- ![流動](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct732wv07pvwx0nmavp5.png) Flowise 是一款開源 UI 視覺化工具,用於建立客製化的 LLM 編排流程和 AI 代理程式。 開始使用以下 npm 指令。 ``` npm install -g flowise npx flowise start OR npx flowise start --FLOWISE_USERNAME=user --FLOWISE_PASSWORD=1234 ``` 這就是整合 API 的方式。 ``` import requests url = "/api/v1/prediction/:id" def query(payload): response = requests.post( url, json = payload ) return response.json() output = query({ question: "hello!" )} ``` 您可以閱讀[文件](https://docs.flowiseai.com/)。 https://github.com/FlowiseAI/Flowise --- 20. [Scrapy](https://github.com/scrapy/scrapy) - Python 的快速進階網頁爬行和抓取框架.. ------------------------------------------------------------------------ ![鬥志旺盛](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k1b2y1hzdsphw43b6v7b.png) Scrapy 是一個快速的高級網路爬行和網頁抓取框架,用於爬行網站並從頁面中提取結構化資料。它可用於多種用途,從資料探勘到監控和自動化測試。 開始使用以下命令。 ``` pip install scrapy ``` 建造並執行您的網路蜘蛛。 ``` pip install scrapy cat > myspider.py <<EOF import scrapy class BlogSpider(scrapy.Spider): name = 'blogspider' start_urls = ['https://www.zyte.com/blog/'] def parse(self, response): for title in response.css('.oxy-post-title'): yield {'title': title.css('::text').get()} for next_page in response.css('a.next'): yield response.follow(next_page, self.parse) EOF scrapy runspider myspider.py ``` 您可以閱讀[文件](https://scrapy.org/doc/)。 它擁有大約 50k+ 的星星,因此對於網頁抓取來說具有巨大的可信度。 https://github.com/scrapy/scrapy --- 21. [Tone](https://github.com/Tonejs/Tone.js) - 在瀏覽器中製作互動式音樂。 ------------------------------------------------------------- ![音調.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fokxsoblaohgs4tx75g3.png) 開始使用以下 npm 指令。 ``` npm install tone ``` 這是您開始使用 Tone.js 的方法 ``` // To import Tone.js: import * as Tone from 'tone' //create a synth and connect it to the main output (your speakers) const synth = new Tone.Synth().toDestination(); //play a middle 'C' for the duration of an 8th note synth.triggerAttackRelease("C4", "8n"); ``` 您可以閱讀[文件](https://github.com/Tonejs/Tone.js?tab=readme-ov-file#installation)。 https://github.com/Tonejs/Tone.js --- 22. [Spacetime](https://github.com/spencermountain/spacetime) - 輕量級 javascript 時區庫。 ----------------------------------------------------------------------------------- ![時空](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abfyfuzt4nw4h7b8usab.png) 您可以計算遠端時區的時間;支持夏令時、閏年和半球。按季度、季節、月份、週來定位時間.. 開始使用以下 npm 指令。 ``` npm install spacetime ``` 您可以這樣使用它。 ``` <script src="https://unpkg.com/spacetime"></script> <script> var d = spacetime('March 1 2012', 'America/New_York') //set the time d = d.time('4:20pm') d = d.goto('America/Los_Angeles') d.time() //'1:20pm' </script> ``` https://github.com/spencermountain/spacetime --- 23. [Mermaid](https://github.com/mermaid-js/mermaid) - 從類似 markdown 的文字產生圖表。 ---------------------------------------------------------------------------- ![美人魚](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggubn86xv7fznxol6fw7.png) 您可以使用 Markdown with Mermaid 等文字產生流程圖或序列圖等圖表。 這就是建立圖表的方法。 ``` sequenceDiagram Alice->>John: Hello John, how are you? loop Healthcheck John->>John: Fight against hypochondria end Note right of John: Rational thoughts! John-->>Alice: Great! John->>Bob: How about you? Bob-->>John: Jolly good! ``` 它將做出如下圖。 ![圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bbuo2ey5q2x3sjwywizg.png) 您可以閱讀[VS Code](https://docs.mermaidchart.com/plugins/visual-studio-code)的[文件](https://mermaid.js.org/intro/getting-started.html)和外掛程式。 請參閱[即時編輯器](https://mermaid.live/edit#pako:eNpVkE1PwzAMhv9KlvM-2AZj62EIxJd24ADXXLzEbaKlcUkdUDX1v5MONomcnNevXz32UWoyKAvZ4mfCoPHRQRWhVuHeO42T7XZHNhTiFb0nMdRjYelbQETRUbpTwRM1uQ2erbaoDyqI_AbnZfjZVZYFVOBCy8J2DWlLwUQHKmAwKrwRo4gnF5Xid-gd2FEAL9hSyp12pMIpNcee2ArxEhH4LG-3D7TPoAPcnhL_4WVxcgHZkfedqIjMSI5ljbEGZ_LyxwFaSbZYo5JFLg3Eg5Iq9NkHiemjC1oWHBOOZWoM8PlQ_8Un45iiLErwbRY9gcH8PUrumuHKlWs5J2oKpasGPUWfZcvctMVsNrSnlWOb9lNN9ax1xkJk-7VZzVaL1RoWS1zdLuFmuTR6P9-sy8X1vDS3V_MFyL7vfwD_bJ1W)中的範例。 https://github.com/mermaid-js/mermaid --- 24.[公共 API](https://github.com/public-apis/public-apis) - 20 多個類別的 1400 多個 API。 ------------------------------------------------------------------------------- ![公共API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjapk9rwlzdl6bcyqdnl.png) 我們主要使用外部 API 來建立應用程式,在這裡您可以找到所有 API 的清單。網站連結在最後。 它在 GitHub 上擁有大約 279k+ 顆星。 ![公共API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rld5i88smezo1naawz7a.png) 從儲存庫取得網站連結非常困難。所以,我把它貼在這裡。 網址 - [Collective-api.vercel.app/](https://collective-api.vercel.app/) https://github.com/public-apis/public-apis --- 25. [Framer Motion](https://github.com/framer/motion) - 像魔法一樣的動畫。 ----------------------------------------------------------------- ![成幀器運動](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hn4ecqkrhs8f4729bzps.png) 可用的最強大的動畫庫之一。 Framer 使用簡單的聲明性語法意味著您編寫的程式碼更少。更少的程式碼意味著您的程式碼庫更易於閱讀和維護。 您可以建立事件和手勢,並且使用 Framer 的社區很大,這意味著良好的支援。 開始使用以下 npm 指令。 ``` npm install framer-motion ``` 您可以這樣使用它。 ``` import { motion } from "framer-motion" <motion.div whileHover={{ scale: 1.2 }} whileTap={{ scale: 1.1 }} drag="x" dragConstraints={{ left: -100, right: 100 }} /> ``` 您可以閱讀[文件](https://www.framer.com/motion/introduction/)。 https://github.com/framer/motion --- 26.[順便說一句](https://github.com/btw-so/btw)- 在幾分鐘內建立您的個人部落格。 ---------------------------------------------------------- ![順便提一句](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnne3lrfpolotmxkdz2m.png) 順便說一句,您可以註冊並使用,而無需安裝任何東西。您也可以使用開源版本自行託管。 ![順便提一句](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rli7hpoccqwpvba29b4.png) 使用順便說一句建立的[範例部落格](https://www.siddg.com/about)。 https://github.com/btw-so/btw --- 27. [Formbricks](https://github.com/formbricks/formbricks) - 開源調查平台。 -------------------------------------------------------------------- ![成型磚](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tp6ggyom33vdifd3m1vt.png) Formbricks 提供免費、開源的測量平台。透過精美的應用程式內、網站、連結和電子郵件調查收集用戶旅程中每個點的回饋。在 Formbricks 之上建置或利用預先建置的資料分析功能。 開始使用以下 npm 指令。 ``` npm install @formbricks/js ``` 這就是您開始使用 formbricks 的方法。 ``` import formbricks from "@formbricks/js"; if (typeof window !== "undefined") { formbricks.init({ environmentId: "claV2as2kKAqF28fJ8", apiHost: "https://app.formbricks.com", }); } ``` 您可以閱讀[文件](https://formbricks.com/docs/getting-started/quickstart-in-app-survey)。 https://github.com/formbricks/formbricks --- 28. [Stripe](https://github.com/stripe) - 支付基礎設施。 ------------------------------------------------- ![條紋](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79yvcgsi4744cmryh15j.png) 數以百萬計的各種規模的公司在線上和親自使用 Stripe 來接受付款、發送付款、自動化財務流程並最終增加收入。 開始使用以下 npm 指令 (React.js)。 ``` npm install @stripe/react-stripe-js @stripe/stripe-js ``` 這就是使用鉤子的方法。 ``` import React, {useState} from 'react'; import ReactDOM from 'react-dom'; import {loadStripe} from '@stripe/stripe-js'; import { PaymentElement, Elements, useStripe, useElements, } from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { event.preventDefault(); if (elements == null) { return; } // Trigger form validation and wallet collection const {error: submitError} = await elements.submit(); if (submitError) { // Show error to your customer setErrorMessage(submitError.message); return; } // Create the PaymentIntent and obtain clientSecret from your server endpoint const res = await fetch('/create-intent', { method: 'POST', }); const {client_secret: clientSecret} = await res.json(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, clientSecret, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) setErrorMessage(error.message); } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }; return ( <form onSubmit={handleSubmit}> <PaymentElement /> <button type="submit" disabled={!stripe || !elements}> Pay </button> {/* Show error message to your customers */} {errorMessage && <div>{errorMessage}</div>} </form> ); }; const stripePromise = loadStripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh'); const options = { mode: 'payment', amount: 1099, currency: 'usd', // Fully customizable with appearance API. appearance: { /*...*/ }, }; const App = () => ( <Elements stripe={stripePromise} options={options}> <CheckoutForm /> </Elements> ); ReactDOM.render(<App />, document.body); ``` 您可以閱讀[文件](https://github.com/stripe/react-stripe-js?tab=readme-ov-file#minimal-example)。 您幾乎可以整合任何東西。它有一個巨大的選項清單。 ![整合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67f3pb2i8xolt635rp2p.png) https://github.com/stripe --- 29. [Upscayl](https://github.com/upscayl/upscayl) - 開源 AI 影像升級器。 ---------------------------------------------------------------- ![高級](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2c1837rev5jb260ro2sd.png) 適用於 Linux、MacOS 和 Windows 的免費開源 AI Image Upscaler 採用 Linux 優先概念建構。 它可能與全端無關,但它對於升級圖像很有用。 ![高級](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4qq1wm3wey3vihn9al4.png) 透過最先進的人工智慧,Upscayl 可以幫助您將低解析度影像變成高解析度。清脆又鋒利! https://github.com/upscayl/upscayl --- 30.[重新發送](https://github.com/resend)- 為開發人員提供的電子郵件 API。 ------------------------------------------------------- ![重發](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3auhh3hbxjmmzehe5v0.png) 您可以使用 React 建立和傳送電子郵件。 2023 年最受炒作的產品之一。 開始使用以下 npm 指令。 ``` npm install @react-email/components -E ``` 這是將其與 next.js 專案整合的方法。 ``` import { EmailTemplate } from '@/components/email-template'; import { Resend } from 'resend'; const resend = new Resend(process.env.RESEND_API_KEY); export async function POST() { const { data, error } = await resend.emails.send({ from: '[email protected]', to: '[email protected]', subject: 'Hello world', react: EmailTemplate({ firstName: 'John' }), }); if (error) { return Response.json({ error }); } return Response.json(data); } ``` 您可以閱讀[文件](https://resend.com/docs/introduction)。 ![重發](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rer9ym187e4i9l11afkg.png) 基本概念是一個簡單、優雅的介面,讓您可以在幾分鐘內開始發送電子郵件。它可以透過適用於您最喜歡的程式語言的 SDK 直接融入您的程式碼中。 https://github.com/resend --- 哇!如此長的專案清單。 我知道您有更多想法,分享它們,讓我們一起建造:D 如今建立全端應用程式並不難,但每個應用程式都可以透過有效地使用優秀的開源專案來解決任何問題來增加這一獨特因素。 例如,您可以建立一些提供通知或建立 UI 流來抓取資料的東西。 我希望其中一些內容對您的開發之旅有用。他們擁有一流的開發人員經驗;你可以依賴他們。 由於您將要建造東西,因此您可以在這裡找到一些[瘋狂的想法](https://github.com/florinpop17/app-ideas)。 祝你有美好的一天!直到下一次。 --- 原文出處:https://dev.to/copilotkit/im-building-a-full-stack-app-here-are-the-libraries-im-going-to-use-51nk

Git Good:分支命名和 commit 訊息的最佳實踐

開發者們大家好,我將分享一些更有效地使用 Git 的最佳實踐。**Git?**是的,就是你已經熟悉的 git。程式碼夥伴是您的守護天使,可確保您的程式設計冒險順利進行,讓開發人員能夠輕鬆地進行專案協作。 你是那個建立分支然後忘記它們存在的原因的人嗎?總是需要尋找*文件變更*才能理解提交?這裡有一些建議供您參考。 我為什麼要遵循標準? ---------- - **清晰和理解** - **協作與團隊合作** - **易於導航和維護** - **文件和知識轉移** - **工程品質** - **自動化變更日誌** - **優化 CI/CD** 在你讀之前 ----- - **分支命名約定**和**提交訊息**約定下的每個 seb 部分分別按**基本**、**中階**和**進階規則**排序。 - 您可以根據用例和相關性遵循任何層級的規則,無論如何,建議遵循**中間規則**層級的約定。 - 以下內容根據參考部分提供的資源進行改編和組織。 --- 分支命名約定 ------ ### 基本 1. **描述性名稱**:一個命名良好的分支可以為其目的提供直接的上下文。選擇清晰的名稱,而不是通用名稱。 例如: `feature/login` 、 `bugfix/navbar-overflow` 2. **使用連字號**:使用連字號分隔分支名稱中的單字(或短橫線),這確保了可讀性。 例如, `bugfix/fix-login-issue`比`bugfix/fixLoginIssue`或`bugfix/fix_login_issue`更具可讀性。 3. **小寫字母數字字元**:僅使用小寫字母數字字元(az、0–9)和連字號。盡可能避免標點符號、空格、底線或任何特殊字元。 4. **避免不必要的連字符**:避免不必要的連字符,例如後續或尾隨的連字符。 例如, `feat/new--login-`是一種不好的做法。 5. **簡短有效**:保持分支名稱簡單。在描述性的同時,它們也應該足夠簡潔,以便一目了然地傳達目標。 ### 前綴或類型 - 為分支加入前綴有助於根據其用途來組織它們。這不僅提高了清晰度,還有助於自動化工作流程。 - 一些常見的分支類型前綴及其用例包括: - `feature/` :用於開發新功能, - `bugfix/` :修復程式碼中的錯誤。通常是與某個問題相關的。 - `hotfix/` :修復生產中的關鍵錯誤。 - `release/` :準備新版本,通常用於執行最後修改和修訂等任務。 - `docs/` :用於撰寫、修改或修正文件。 - 例如, `feature/new-feature`或`release/version-1.0.0` 。 ### 包括票號 如果您的專案使用 Jira 等問題追蹤系統,或者它根據 github 問題或其他類似工具進行修改。在分支名稱中包含問題的令牌將使追蹤變得簡單。範例: `feature/PROJ-123-footer-links` --- 提交訊息約定 ------ - 提交訊息的最終格式: ``` <type>([optional scope]): <description> # subject [optional body] [optional footer(s)] ``` ### 資訊主題 - **命令式**:以命令式建立提交訊息。以動詞開頭來指示提交的作用。 例如:使用`fix: Fix bug #67`比`fix: Fixed bug #67` - **簡短總結**:嘗試將主題行控制在 50 個字元以內,以確保訊息在各種 Git 工具中可讀,例如使用`git log --oneline`時。避免尾隨句點和不必要的單字/符號。 - **將描述大寫**:這聽起來很簡單。主題行以大寫字母開頭。 ### 類型和訊息正文 - 主題行中的`type`前綴可用於表示提交中包含的變更的類型。一些常用的類型是: - `feat:` :總結程式碼庫中的新功能。 - `fix:` :修復程式碼庫。 - `build:` 、 `chore:` 、 `ci:` 、 `style:` 、 `refactor:`是其他一些例子。 - 可以將`scope`加入到提交的類型中以提供額外的上下文訊息,並將其括在括號中,例如`feat(parser): Add the ability to parse arrays` - 可以將`body`新增至訊息中,以在提交中包含詳細說明。 - 在主題行後面留空行來加入正文。 - 將正文包裹在 72 個字元處,即。使用多行正文,每行不超過 72 個字元。 頁腳和擴充訊息正文 --------- - `footer`用於傳達有關提交的附加訊息,例如審查者、批准者等。例如: - `Signed-off-by: Alice <[email protected]>` - **重大變更**: `BREAKING CHANGE`是指程式碼庫中相當重要的重大變更。可以透過加`!`來表示。在類型/範圍之後和/或透過將其加入到`body`或作為`footer` ``` chore!: drop support for Node 6 BREAKING CHANGE: use JavaScript features not available in Node 6. ``` - **多段落正文**:在某些情況下,多個段落有助於更詳細地解釋提交的目標。範例:描述提交更改的內容、原因以及方式。 #### 例子 可以[在此處](https://www.conventionalcommits.org/en/v1.0.0/#examples)找到提交訊息的各種用例範例。 結論 -- 遵守 Git 約定類似於說通用語言。然而,很明顯,這些標準或約定並沒有被任何系統強制執行;因此,這些標準的調整和擴展使用完全取決於我們。 養成這些習慣肯定會改善您的 Git 體驗並鼓勵協作編碼環境。儘管我們不能一下子就遵循這些,但逐漸適應它們無疑會有所不同。 我計劃寫一篇關於**使用 Husky 實現 Git 約定的文章**,透過反應和評論來表達您的支持。快樂編碼! 參考 -- - [Git 分支的命名約定 — 備忘單,作者:Abhay Amin](https://medium.com/@abhay.pixolo/naming-conventions-for-git-branches-a-cheatsheet-8549feca2534) - [常規提交](https://www.conventionalcommits.org/en/v1.0.0) - [Git 約定](https://se-education.org/guides/conventions/git.html) - [如何透過 CBEAMS 撰寫 Git 提交訊息](https://cbea.ms/git-commit) - [Git 預告片](https://git-scm.com/docs/git-interpret-trailers) --- 原文出處:https://dev.to/shinjithdev/git-good-best-practices-for-branch-naming-and-commit-messages-oj4

用Github Page整理作品集

因為一直找不到工作(...汗)所以來整理作品 [成果展示](https://superyngo.github.io/to_do_list/) 基本上是參考[Let's Write](https://www.letswrite.tw/)做的[Demo](https://letswritetw.github.io/letswrite-food-check/) 在頁面下方有作品導覽以及Github連結 使用工具: 1.Github Page 2.[Google Tag Manager](https://tagmanager.google.com/#/home) 步驟: 1.申請GTM並取得GTM代碼 2.將GTM代碼插入所有專案的index.html中,並將所有專案上傳github,開啟page頁面 3.另外做一個myNavbat的github page,將所有專案連結放進去,可參考[我做的](https://github.com/superyngo/myNavbar) 4.用GTM的「自訂HTML」功能將myNavbar和github連結塞進所有專案中,參考代碼如下: ``` <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" /> <div class="myNav"></div> <div class="github"> <a class="githubHerf"> <i class="fa fa-github" aria-hidden="true"></i> </a> </div> <script> var githubHerf=document.querySelector(".githubHerf") githubHerf.setAttribute("href","https://github.com/superyngo"+{{Page Path}}) var myNav2 = document.querySelector(".myNav"); var iframe2 = document.createElement("iframe"); iframe2.setAttribute("src", "https://superyngo.github.io/myNavbar/"); iframe2.setAttribute("width", "100%"); iframe2.setAttribute("frameborder", "0"); myNav2.appendChild(iframe2) </script> <style> body{ background-color: #fff0df; } .github { position: fixed; left: 0; bottom: 0; display: flex; width: 100px; height: 100px; cursor: pointer; z-index: 2; :hover { position: absolute; left: 10px; bottom: 5px; font-size: 3rem; color: #fff; scale: 0.9; } } .github::before { content: ""; width: 0; height: 0; border-style: solid; border-width: 100px 0 0 100px; border-color: transparent transparent transparent #6e5494; } .github .fa { position: absolute; left: 10px; bottom: 5px; font-size: 3rem; color: #fff; } @media screen and (max-width: 600px) { :root { font-size: 12px; } .github { width: 70px; height: 70px; } .github::before { border-width: 70px 0 0 70px; } .github .fa { left: 8px; bottom: 4px; font-size: 2rem; } } </style> ``` 注意事項; 1.不知為何我GTM塞iframe一直不給過,所以用append的。 2.iframe內的超連結預設會在iframe內開啟,要避免只要在myNavbar的head裡加上<base target="_parent" />就可以了。 3當初做這些作業時完全沒考慮theme和RWD,花了一些時間但又不想花太多時間結果就勉勉強強用手機也都能開。 閒聊: 前陣子都在codeSignal上刷題,看別人解法真的很神,學很多... 有沒有北部公司缺人啊...投履歷都沒人回..中年轉行真的不行嗎...

JavaScript 系列九:發表作業&心得分享

第1課 ── 學習 Vue 元件基本觀念 [作業](https://tinyurl.com/yst8ytys) 第2課 ── 學習 Vue 的 props 觀念 [作業](https://play.vuejs.org/#eNrtF11vFFX0r1w3MW0JM7MYiWRZQCE+YBSJPLo+zO7c7oydvTPeuftRm000lQCWpESMoCFRowIJKU2MMVWqv6azLE/+Bc/9mrl3dtvSiPHFPmznnu9z7vm6a7U30tQd9HGtUWtmHRql7GyLRL00oQy9s3reD7r4MsWDCA/RMk16qFVzPRvOuVu101WuGfKCrkXwSFAGeNnvxwyttQhCnQTYCSYsa6C1iurjhdDxcU4b+MxfXJJ8CFHM+pToE0JpkjGQoY9cdJzQBtgyDCMGNggZ8o/hEbug0e3Y76xY6Nhv45ijLChN+iTAQQUuTeN/bW7qmyO/l8YYvHn/A4UZg/OarodZmATcV4lL+0xxlI6BeWGUuZY4N+1n4eIacl1XILmzaLwkJEtfSZbE2I2T7uIst6aTNsjfoc86YWmHHbwA47SBGO3jwrvQJ0GMqWkmBCrp+PEVllAfLjrD7CLDvcVWrSevjV4GqRAq9NaVdy+5GaMR6UbLq9JArnGpdECHUf+vBPMFWVagEb93U4V102iuxXZIS+r9nFA3DlnDcFBaV97fGakm9WmGFy2Du/uEcmkJnTtXSlCKZ61DZ7RJh2uohMFQYWGKJObp3PSKpgEHkJPGPsNwQqgZRAPUif0sOwOyk2C1VRPwCiYikPoXEsL8iGBa0ACVKL7iiND00cazT3cmt69N129Ovt5+9v3m9MbPJbopJCG2mmIQK2q+VSvUiPNFTgHAgdNLAhwDmAfP1bReqduzle9vy+Sra/nWnRdnS9GQDrZHyDc6nJIsqJRko8lJM7hoE1zRLHhNPFxlB4dJHGAKNODxdHcnv/qTSIb86gPwvKQ2TK2GanJ3O791f3LvRn7v9vTBFzNB0rarrqrjomMX4s5KOxnNRkrRmzbMhKndZywh6PVOHHVWOGPRZSHR8q27k+u3nm5/tvfnRtOTpDpDPUjRedmayoE0N1/DE2fVvGp68F3AK2O0UZyTVIgUBW1GEJh1sdmSTEuUlLJejZBrlXJ+AfElPHxbXq8chjzcPHR6lBnaD+Yu0vNoEgy9XYoxOYTPbMADZ1nwmT0IJcv2XDDTFqGGVmvSzOY3EJruWMRGGVoM2guLWNW3Rajcq5LOJK1VOmbWFd/6q+kZ7RWOGVuN+ecxOU96Pu1GpIHqoj+nfhDAyJLHcYu4vAFrwpEzjAIGM/9U/WVB3YuIE+KoG8LoP1XPBqGABlEG6lYbaDnGI1PMWaR0coTT9rMIBvOJuhDGieyWLkmrwhRzEFHcYVEChkMU+z0iUB/2MwbT1oFlhsFGCDj4xVTg/DjqEgf2uB4oNeBdH9aBExT3lBHVSv2PzKiU6YFWDCln5r/zRMGoVTdeO66rX2/uLzkOH0n5k9+fPtrQyzJHovzq+t6TX//avbm3c3/y5fZk85e9nY38+p3882+n63+0iMhdBJ/5j99NH27lj7+xpysvBAhAlcgee6K05uBhSuSPf2sRXeuThz/ku5stkm+uTz9Zb4SMpVnD8z7q+5lP3QAPPDAZtOmXgCdqx0OOo1Je7xrzHhAp76fFgqh2/itic1PbmLHsW3C15VuwYsc/n8A67ZNikXuOrUdZoFcf4/513TfEVQKyWFTb8PToCqUiBRNabKHKk8L48pmRUBjN7/lB1Ae/dYzPoYWT9XS0gBpoob6g91CpWPWWtTXpMhpDWh3eYKz1T8Y3hooqOkbdVUkKaQyV4mTRx5hDT2loke4REYxtWEBXBEa6AFmejhA8W6IAiTdYKWuodLxWr/Y191Ut3juGBpiyCJZaR5QlBCtJT6Nj3r51Yzxd/y8fu3zKp7c8j/9B1qswP1/Wm3rlSK2WgEVxWD1YxHOLA/7vVx4W89FrRa96s7Uyr1Je+Xfr5OTR62T8N2L3XWg=) 一開始方向錯誤,沒有懂老師出題的用意,就照先前的想法做了控制面板,後來才想清楚不是單純用vue做東西,而是做出quasar這種開發模板用的componen 第3課 ── 學習 Vue 的 events 觀念 [作業](https://play.vuejs.org/#eNrNV1tvG0UU/iuTVVHsNL7kIUJaArQplwgRhIjEC4vU8e7YXrI3ZmedGMtPIaJtIvJAaWkkbiK0qaqmCCGakhT+C/I6zlP+Amdmdta7rhPaChCWsto555uzc8755ptJR7sYBOVWRDRdmwtNagfsFcOz3cCnDC225yPGfA/Vqe8iQytXlIXPMLSXDM/wyKrAWqSOI4ehjuEhZPoQwCMeC3XUGYbpTnOnhRkuFCUQIUpYRD01QijE7QX7bTtkOvpA2dDQzX8BphD69RY8dMSadlgWk0Rw9XNwjTg6rHnRdw0t5zJ9x6fcRYk14mJklV1S7gYlxBsBhPYnREfV8mzOSv3Is3RUx05I8vCPI1grLJJGWYesw1NltmyH4Xw7HzXN7TU8mkCam2M3mqzm8C6dnmEQ0cAZRagUXxyX4kgiwwxHc3+GFHmdme01xuf4FjaXT0vSwnQZZrfPzNH2RufLDGeeKb9/qYOLtIwuehahoT9KtXwr28Rx/JWzEh3T7P8XW8+flmDNebLHudRWmjYbn9vYJj5XZv9EhqX/KsPn2IYfJm9dEG1ldwlr+hbXaOkTMlrwUm1GCDuEsoKhLdiwSHQeefBnaBMThlYUcYZfSAozdjbY89P//HrnZH/rySBKCsZGeTNxnr0S+VzBzGxCXnLEj6OIEShcYnChjDDmpxA38JrMVdLTDwaMuIGDGYERQnOW3UKmg8PwZWilb4HeCDt41NGm1toq1X0KKAcOMOTXh6eZoSnIBUmqEuGsSqDlDNGGSF0QS0HEIOMU5FJOMcg4OblKOURKtwyKM0z5+XvGJYimfGKAXhW0QwnJsmEE+dJAYnQKuiILWoGKwttcJVNnGIas7fDXKdl8F9OG7YGAiQYH2LKg+7AjKHHB0jW8Mm+GxK7YFoOGz1SrLwh0k3DVFIaw1RQmyw7hW21YkUNWhaWBAyGPMiASjtIK5Vb+FDYM8uuVYHe6sE9ChimT3wa+JKvVprXstYhfpCZKJTS4t9F7/MfR9d1476v+jUdH25/G62u9g18Hd28ffX43fvhjvP7w5HD7fSjS0huX0LuwtIYoNC9Fk7Eg1CuVsG7ymB+FZZ82KtzDqwih44Pfju5tpFcrDkIy/snhZm//dv/6g/7WL739jfjKzfjat4O1x3Kq4ASCYbzz3WD3fry3PVjb7N96cPz91uDqzxIzJE8O2L/xWXz/ZhYoKDkGE6/fifceJZoCvMpDNq8eX/ky3rkT/7SVXAEFvfq7P8SHiSXhUNZ0wXRsczkX6fjgm/4X1+LfN6G2vYODeOMWKpU4rdKdPO5uGlAfSqvkJZHoJUaHN5CMMufsic7nbFKk34ncGqGJKdHoed93CPYULhHorPVppKeWkRclQa4SnWRTydKA4xxxbVaYzIjJ5LRcdVFhdcFawKbyWoOjSRJPl9VIj4ykNmk5UkfNp3BleQ9bdgSVXMSsWca1sFBQOjFbhX1fLaISKqRqMCtMRVDtyWB1Mg3l2B5ZSPbqZRM7ZuFch9e0i6aSnVm8nILrvseWRMFz0CkhCRlcKhV/G1FmMg5YFUgU+o5tIXF+q1ldWUt5BHQ6yS7ogiZwZZMNO0Pcyqp9koLZ8nvwP5MQnWRZ6diM4IJI9cC34diiifipOHrTbxEKwQwWQhpEnynP8HUKiuWEqvsXUnaEYQ==) 嘗試從quasar的原始碼反向工程做出一樣的效果 第4課 ── 學習 Vue 的 v-model 觀念 [作業](https://play.vuejs.org/#eNrNVltv3EQU/iuDVdQN2mtuTc0m4iIh8YAEqtQXzIPXnt012B4zHm8SrRa1TSuVhrA8tAmKkKDqRakCSSsQDckGfgzr3eQpf4EzF3udTSraPvXB9pwz5z7nfOO29n4QFFsR1nStGlrUCdiC4TteQChDnyx/7AcRQ3VKPGRoxZJicHlDe9fw8ZKQs3HdjFyG2oaPkEVA2cc+C3XUTk108nzPNpmZm5ByCFHMIuonFEIOl7xquhHWkR+5rlBBqAOO4C0oD7MmsbllSS+azGqmFHcdMWynDI9EPtDcJWdwS9VSmiUQDHuBazIMFEJV22khyzXDcN7QasReNjTBhx2VRhKp7hEbuyJUEB3FbWiJxHtRAMni04I5Hy+K9QSaX0C5kR6aR+nWyIZr1rALanXHdbE94itaUKU3IkISMdfxszGmnEyU1RIUGFbVUqbsQIZs2eXLd2QreCZtOL6OyuLcA9O2Hb8hyY7hF/nBSMFFx2Zw+JVy+W0h2sROo8kEI2w1Bct2QnC0rKO6i5cEhy8KtkOxxRwCXiziRp4vtmqm9VWDQsvYBeASqiPaqOWm5vJo6hJ/JmQE0EEqYC2vZSaCT9BbhQI62l7tH/4zvLsV7/w4WP9ruHkzvrXSP/jz6Mnj4fdP4ueP4lvPT3qbV6GoVz76EH0K8UmvvBhNxoJQL5XCusVtfhkWCW2U+A6vI5iOD/aH26vJXHEZJM2f9L7r7z0e3N0ddP/o763GtzfiOz8frRxKzVZBnDMCRvzwl6Ot3+Kdzfha799r1+Puevz3BqyloDjSU2KDX2/2D9fiH9aGW89Oerfj7m7/4FF/b41nuNJFn0VmaFIUr94b3ts+vvFgsPXgqLt7vL8BAcVPnw2f3o/Xd47v7w4f7sc/bQ02rh/fuBOv/Q5mTnrfSp+yoRFoxr2uZCX9o5ioUFC9kgzvedATUALFSwBFZKKjK4xC/ygskZ509AEhLjZ9xU2cjfNHo8GhjC0H8FXmEscZuFIQJd/YczgAfm5oZ8bM0L54RSyyiM9MCJCOAElMZgqcdjLjowHUE+V2mrT85jPpplXujBR5mqDG8FLWWksBRDaNFEmEa9i8wLPOXTyT8cU8uoBbcCUUGcw2hq4dwxGKv45gJMcxTfZindBRegvttmrRTqdaEquXwpZiWkPVKiR0JABQDNJOCwsISLBnphxwuIBpN3zpbkzLrIUAHExqubguYEfoQAVJkKWo6ada0CWT5bIXIl52kwqBDNZU5qbyqHLpsngpuIHbWNygWcgDG8p6Co+TwHlppyOzep1YUYi+kUWFvpRcOCDHTrjStcgqsZ+JeW4mjyYrk/CameEhIxRapgszUS5eTlwV1YSrH4QX55sFYSkyC9A7O8sftU+ojUHdh3+MDKNQI4wRD+oAZYCjgejP01YNn6rzC0WNR5O0MIUCJLQsjIj4hS4Wm45qAVBiPKwa5XeQj8MwVymKesgCpJP2GiWYhhtoGpKYHitB5VSq5xg6L9t0+NN8U86ZjMddnD3q1MP/CZ5bn8rZG7XzH5rEyeY=) 同上 第5課 ── 學習 Vue 的 slots 觀念 [作業](https://play.vuejs.org/#eNqdVd1uG0UUfpWDEeJH3o0TCqkWUylBofiiroQbIaS9Ge+O7VHXM6uZsR0TWSoqkVADBFAFFarUIgpEKj8XVCjQwtNk3fQKHoEzM7trO2mo2ht7zpnv/M45325X1tLUHw5oJajUVSRZqs+FnPVTITVcGK8TzqmEjhR9CCv+UqExFmHljZDTLYuMaYcMEg3bIQeIBJpzyrUKYHvmZFI1lzHR5KWXHRBAUj2QHLYn6ApyRJ/qnoiNrZNHREe9UjLOB5rGpaIvBhxl49MojKf6UlkJCpr204RoihJAPWZDiBKi1JthpS3icVixerwpE5XoMaZxrgd4j0JE+IsaOozHMBYDCYoMaYzZRyylCjABlpgLUKzLgXHfBHbGZXgYeioROiCRZoKXzhHRHmiNmrcuNi81mpsbsNaCNTi/udG6VF/K7wpMq3G+CY1mqS+jLC1UaRRFObYJ/19go+OSJyPQPaagbWFVFGh+xkdANWW8C4pSDu2xsXimMt/faJ0oq3nxhOrfWzduPGWZRsTnxdMCDkWlx4k5vuLmrk9kl/EAanbqUhLHWJgTJyH3zVg44IjFGkdvuVZ7wUJ7lHV72irUsGdVMVMYaBxAV7LYarokRYSkfSuRBEfCiwTOKEdLpYnULk7IXXUuVFvImMoAOG6ONWyT6HLXvlSAE9Wjkhk7swCJQBz6jWg7GThwB/17in1AsQr/bBE7GkhlsKlgGF4eq9Z/rcClQjHzWgFONDaNDY1TzNDlFwSkg9bFbueFhBW7//PGpK1Egrtp1YwrijDX4lkt2Amb/qjHcqBIScQ0NtBBtSS8cJhfYaorChLGKTE1zLUu6IkhNm0+wZk7f8WBkQ3y569UK/MEZijvOc+DkB/d3c3u//nw7m7JVuYesp2rh/d//+fBJ4cHP0yv/zrdu3d4sJt9/HV27dbR1b9C/uj250f7Pz/85iMwIw+oy+7cnl7/O9v5Ptv5KfviWrbzY/bLHyF3yzCPym7uo6/DgyvTz76c3ryS7f2WfXjPmT769tPszleFab6rMN3/LnuwB55nxrukt8fRbypFapk3Nw1gXYiEEm759Wn40Tw2wbbLGUma66C4nwuRH6o5XwT4jtjACRrWTdXnMKT7cwta+ipcuQ4VcOCkTxe0x82ftOl+mXvelFNG3M/5LeeFLW+28mo4esxurZZbY/WjnBHO1Nz4min1SprwV0p0QjXOqKfMeLr1qy2vnn193leH9FmCk/uuaAstquCRNE2op8YKa6zC2pByhqy8jjEuXyBRy+rfRssqtGhXUNhs2C8iwDs0GVLNIoJWkpGkitzOlaeQRDqnLOTzq+3lDjErcwrFlMRhqC1nD3jVlWcamc/4sW4vcIIWyIy5CX77XZNKuWTSTkK3XFfw4I2k4VPze4JdLRP4xYbM0agnScwGuARnUuNpkQQm/wFjNTqv) 嘗試模仿quasar拼裝不同呃component 第6課 ── 學習用外部狀態管理 vue 元件 [作業](https://play.vuejs.org/#eNrtVktvFEcQ/ivFhshrsi+bWEo2hgBOohwgQiBx2gO9M727HWamx909axtrTwQFsBUOIRA45KEQHkJAFEUBYkj+jGdtn/gLqX7M7KyxwcohyiF7mO2u/rq6q+qrql4uHY3jWj+hpWZpVnqCxepwK2JhzIWCE0vHEqV4BB3BQ2iVavVMone0Sh8UkB8xEvBuEWklObIV0UWD9WmHJIGC5VYE4HFUENFIySYsw/wxFTXzYyswb3VokdM/qOhdPlGkPGk1AAiqEhHhdhJQoZrQIYGkFVQddZgI3RwGeAdw+0OqetzXR1oNZuPU9MGRTicro3DSbMy22u8CUV4Pt9uZNiJR1M8FIU8inGt1WqCPnq3n3sWJomEcEEVxBjA7X20rlOpDAtKmwaFW6ag+vVWyQo8HXKCwHRDvXCZUdFFVs5WFHlPoZrvSlOw8ReFUJhB4Hd8Oj8REoLertI9fxBgr4RDsMwO74fBs3dwou5xvXd+vhtw3l3NYs44In/XdEOA4FzQEFsskBF9fDiRTQNDhOh6SekoHC4jPYiaZx6Iu0ICpGpyiArcIGtMgoJGfyEyj3t/nQRIr9Fc2kqANYKgVKSV4th0dFPlMMSYhpqJD0VQfx4orEprA6B8lQBTwMMKVPg0gSsL5hIRAF6nwGJ7CkJAhkERVICIqkRAy5Dmp2LN0iNDImjO+PrK+GMdRJOeOc5mHZpdYvi6aO8RzLKJ7i6n+dQJO9Lpg3V4uHg82jm20dyXmnM2qf4GaLn+1IW64R3rm6P8J+t8k6G6R/Qckna0XSilOpVoK9PCALeQhEV2GLaVhanhMfB8DaqeDVtTm/pLFLTBfYT2fajTeNsge1ccbgez3jKiN7ugas6wbmvDWND3oHaRWF9Z3d3SpUio2v7HGulMLjAWPTfcz/D1DgoQ24RjnASWRaTdvah8YYPACIqV1rSIsoqJVwoxgHRSN1I5lRL5F9ojPF3BtjCpFxAKLECE1RAZcIdD9ZfhstFs0avm1nMkckwZZ3ATSlpgwSjsRgGH+odNtsDAvUNNSE7qC+TZ8yEiKzsfWGiHMwy8V1vujA5pt2kH2Z68Lh0Ui6TfI3k5+NdKi2y5PvT9dgemp9/Az494EPCaYj3jFRm3GCDoswCs1oW3YG1Epy7hkweer6EW6mJOv5rzqPJJRcwrL025863Q6Zikki1XH2JlGI160eC58KqoCK1eCdHrXifNjp7Ydexi250htxp79KptHjz7N5n3VKmw+WFl/8dfGtXvpo2+H159t3PoivXhhfe33zft3Nr66nz75Ob345OXzW2cSCqc/mYOTGElrjOZFTylkfL0uO57W+bmscdGt6xVNPVSdrv2x8WAlfwhqEFj9L5+vrj+9M7z2eHj1t/WnK+mlG+mV7zcvvCh0I8BpevuHzXsP00e3Ni+sDm8+3vrx6ublX7c3pzHg8PqX6cMbRaCpjztg0ot300fPLEYXvnHI6uWtS9+kt++mv1wtdDgY3vspfe4kEqs5MrQoOuIFzDs3pmlr7bvh11fSP1fRt+tra+nKTahWdY7tqZgU/NGE00ogt1x/0fbP7SA35m6TafOa8FkStqlwIlOft8GMiXnNyvYaK7dL+3MBdpuTMY+TeHxtL5WubejgbHPFKXQkyXqFdSUu7KchU+UJ23s+1q1nomKtnBw9RzTLEZu/+kdZhwVGeynvys6XufvyBZt4p1zenSCqV8PaUi7bwH+IKQqYXJNQhbKLPMqMaBLegYl4cSJXFWAF+9S1nrMeCbzy/mUdgwHmqk3PybM5uIPF7bQJ0Bj0gCkhBVxeWt6o0VqyE7BhkIAVk/n6EeOdK9zDMsL8OeHAvdTsbHnZ5dIAK4tuFjaMr+sXWVAtkYtBifDtU6h3BYGXCKkjFHPmGgOSXZAoK/gSraIw3WiE+Dgj0vXt/Khmj/ez/mSgWDJrrmgWyuHgb/u4VhA=) 稍微翻了quasar的原始碼,還是搞不懂為何上一個v-close-popup的attribute就可以讓按鈕有關掉modal的功能 很神奇 第7課 ── 學習開發狀態複雜的 vue 元件 [作業](https://play.vuejs.org/#eNrlWdty20YS/ZUJJSekQ4CgHMkWLXkTpdbaVG22UrJrX0SlNCSGJMoggABDijKL/57TcwGGAEQ5l7fYLgno6enL6Qt6xtvOD1nmr1eiM+pcFNM8yuS7cRItszSX7Lcf0zjN2SxPl2zc8Qc/PyoCsY87b8eJ2Ci2UMz4KpZsO04Ym6bYm4hEFiO2tRJ2fVoKueTdnmZjLBdylSf2jbGF2Iyg5SgYBsM3b8YdtYWxHfTgp3pbCrlIQxKs3x+4nC7KN9K8kiIsCct0leCdVBKBJF0MSh/xIsUyi7kUeGPsIozWbBrzorgcd6ZpInmUiHzcUYtYnqykTBP2/TSOpp/AAnvZJfvm6L368w0YpSjkxUDzKQVqH8QaEXj5zZsqQNbeMg1FrMWMO2xgtQwsu326GDhW4rWQjzE9vtTILXk+j5IRCxRMGQ/DKJnr19048Sdp+KgZH6JQAqthELxQrAsRzRdSEYr1wrCXbus9pbhhkG0aLO9YzYaKCzAbMzv9jpM1e0nWlj2HUySfT0bs9s5kBmNrHkfhzfXVHtHkUWsCZXmaqbxU6P+fxysxYh9kDicNh1hGlLm3484qgzFiVHGOO1pJlYVaARR+TG/mky4eStMpHZNC0uIN0gS//GI1KZSq7rDPXvWUWXuM1w3GV3122sJ41WA87bPXFaPB7TbjeSF+SiRZdtNnw7NeHzGtaNcttCtFuzOyNCgK+Y/pf8Smi4enfPzfajkROXHcBnc9X6Ya2C7E+cikD5LnsnvSR2yCcecJ9x0Zwz8jg5BxZJz8ARkGtPuj4y05tFO/rvWvq919DRBAj0yphXww+CRExmZRDmtiISWq5MguRjPW/Wrw61H3NvDOf/De322D/tmudzyIfGocSpQjizG5iApfdxm0RTSJb5tpZHn8WCRzuWAeG1YeoRAr1Xuan9d7TIXQba2CPpnR0GKBUTWJLShLEwjhSAcoxLESVZyEj4DMhfQVvZJLRhsWvcLeXbKAff213WioF5fs5PS06YGJkHou09e+9So9ht32Ehh26/u+ZbSFAAeZiAvRUAMed4sV4+yrVZIohASSUUj2OGY74VaPFeS11FvwJIxRrvjY/YjnuXCl6EqY8Fx/eGFZZe89bO0eb63ZqNJdnwX417svu6fhAtVhHCrGNq6g77Cd3O0cngoBbRN9OHI+/XR1yLafuVz4fFKUgYKRSGoK8GFbmxuH7sanbG9uOym3tfqiiyMXM3AT9ioM/izN/82ni25XxH0WJSF1hct3bq5oDJZRArdF7OPBSUCzyCn2tMjpM7q/iLzSiyrrnWWQ1LfWR1r9gs+byOUj6tbzkANq1qCCtflwq2y7c5N/MGAQfB/jk85zb57zMMLwhlDU9gDFJq1n2+KeJRNEeZ5j+Ao/RJ+p0rtUq4AVXvcwNGDk6LEB65LDhvgtWtwLNZyowdJUTmWnA/tDzjN42dD105LPSdk9AIumlSdqevXOg1DMy3geb+vZSMXAgheHOFAF7NWrgyyoAHZ2dpCF9JCfJXS6rBsTq15sazEItNNgnmxeLWyHuotGGEOZ/Ij5tgsT3ATW25uNx/qgHxpzuPlWKkvcLmW+tdYoPT7V7Cpl27YnNu8BpkLxKVmmYbxkgX9yfo6scrsBUU/fvHapKHaiDoffsXJGZ2z45qx6+RcycxIjghgpSyINmA+LSOpjUD2K9liiV9xRszrsKCj3/PiSYP+BgH9R0J8P/BcEv1aqNl4VIs8dvL7yPHZRrOf2DCRhC9vgbHSKAY092gd7NqNlnLa2W0oJttvRCWlDgunQRGKY5zVPdKZtQA66iPtutbrMEGyGneroFpHrlcdaChh/4YmI3eRwhCi43DX5mInShYpcOw46iYYeqUc7rL3eW1H9D1T0O1TESM2pZYHs3laN0VMUMFTh3729d2V9r3yDLGeq3VufxKscy7XZpWJpHl9rgCIxlY4C+K89fC5B60bltzKd0QnDRbvIeFLuxtp/+YRQbritqhDOOOWLxMDx7Ya+e+POtf51hcOb+WghY0otA1LzTIirz3xbkNtXTZjVokvHtw5kJLND4pTpGDja84G6lLb7UMD2jmctcWn6Zu1P1CzdcOCLDWiO+8dijc/uweT463cbjE3SjVdEnxVlkuahyD2QzCWFKe69m4+TQF9PwKCXZgeuLLINK1K4QPlHByr613vLXg5KHQsepg/Qir+n4AYfp5FTzaLGEqWd5o0VbgW+M1qqyxNs05S0iGSUwqNcwOloTW3YMXc0EagMc8SgwQE46qsMtT1KUH0lGqUsTK9pjO+tIn/2VKxKkKomoMuFqXpRa2nGp5F8BKt/ou2AJbZnaRvSlaS5cMQS3Ojt3RqdWizr10rU2TxMPEkBV5YjtiLHprzQ29UqMmYOu6fwTuSKPIOv3oMRfR5o28voa+D33RseBrRsN+Yeq43PiRDFVSutKQijAukJjGax0BYo4z1guESoSxdIZ9UJTABXeUGIZ2lUOlpN5SOmQMLNC2Q4aeSmZBUrgDP5FAE6oMmxb+rGxIbAXL9Z5LxYzNT93j41t9d+hlxG1LxXKQO0KNfRmvp0IDI/Av/MpH2VWxGN3iNWP0Osed6tPMY9U43QWj5NO6jMIf11oA8I9dVcABM4kKTm0SYzylyH4+MCnUmVtBOk0ciCWgBrGCAVlwrdQbjLi1NrqcW/tLzmUMPkUR0ItW7zRTzAD3K5anNOCzqhVG3d/2QxPOfzaJGuba8spjyGs0Nf539bA2zT3lCzTD8DABD+IbDW/P17IFUt7HZ/lrgjZcU/BVXj6N8DJ6Q7087+bHBm4HjiA0XqZzHpWERhKOjuZv9/OXa/A88llUk=) 研究了前輩的作業才發向若要讓input的值可以被檢查就不能限定number,要不然輸入非number會直接show出來,卡這個很久... 因為想學quasar的樣式(range條的顏色變化等)做了些研究,後來嘗試把所有想法塞進去,結果做出來是蠻炫的但不是很好看... 心得:覺得老師的出題方向就是幫助學生從業界的需求去學習,然後一點一點從小地方開始做,並且能夠自行研究,而且不強調怎麼寫,而是確實做出來,很務實的取向,覺得獲益良多,上完9堂課默默繳了不貴的學費,有新的課堂會再回來做。 目前正嘗試自行開發一個網頁應用,寫cdoe真的要很有耐心,其實想想現在有很多輔助/查詢工具真的很方便,越寫越佩服那些做框架的人...

[作業問題]HTML&CSS 第6課 Loading Page

您好,請問幾個問題。 1.為什麼我使用position:relative,網頁會出現很大的空白,我該如何解決。 2.使用絕對位置,我該如何讓我的網頁隨著比例縮放。 問題1 : ![](https://i.imgur.com/wzXvqGk.jpg) 問題2: ![](https://i.imgur.com/4a7OA6u.jpg) ![](https://i.imgur.com/BzUIBdJ.jpg) 這是網頁全開的時候 ![](https://i.imgur.com/YGNQAfx.jpg) HTML: ``` <!DOCTYPE html> <html> <head> <meta charset = "UTF-8"> <title>佳加安全帽</title> <link rel = "stylesheet" href = "style.css"> </head> <body class = "page"> <div class = "navbar"> <div class="container"> <div class = "logo"> <a href = "#"><img src = "jiajia.jpg"/></a> </div> <div class="menu"> <ul class="choose"> <li><a href = "">所有商品</a></li> <li><a href = "">特價商品</a></li> <li><a href = "">安全帽</a></li> <li><a href = "">藍芽耳機</a></li> <li><a href = "">裝備衣物</a></li> <li><a href = "">配件</a></li> <li><a href = "">包包</a></li> </ul> </div> <div class="user"> <ul> <li><a href = "">Log in 登入</a></li> <li>|</li> <li><a href = "">Sign up 註冊</a></li> </ul> </div> </div> </div> <div class="background"> <div class="content"> <h1>在危險的世界中,給你多一份安全</h1> </br> </br> <p>留下您的email,獲得新商品及最新優惠資訊</p> </br> <input type= "email" name = "email" value = "Your email"> </br> <input class="submit" type = "submit" name= "submit" value = "訂閱"> </div> </div> </body> </html> ``` CSS: ``` *{ margin: 0px; padding: 0px; list-style-type: none; text-decoration: none; } .navbar{ background-color: #272727; height: 50px; width: 100%; } .logo img{ height: 50px; } .menu{ position: relative; top: -50px; line-height: 45px; left: 500px; } .menu li{ float: left; } .menu a{ color: #D9B300; display: block; padding: 0 10px; } .menu a:hover{ background-color: #D9B300; color: #272727; } .user{ position: relative; top: -50px; left: 800px; line-height: 45px; } .user li{ float: left; color: #D9B300; } .user a{ color: #D9B300; display: block; padding: 0 10px; } .user a:hover{ background-color: #D9B300; color: #272727; } h1{ color: white; } p{ color: white; } .background{ background-image: url("motor.jpg"); background-size: cover; background-repeat: no-repeat; height: 660px; text-align: center; } .content input{ width: 400px; height: 40px; } .content h1{ font-size: 40px; } .content p{ font-size: 20px; } .content{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .submit{ font-weight: bold; font-size: 20px; background-color: #D9B300; color: #272727; border-radius: 10px; border: 0px; } .submit:hover{ background-color: #272727; color: #D9B300; }