🔍 搜尋結果:Can

🔍 搜尋結果:Can

如何讓 AI 融入您的使用者(Next.js、OpenAI、CopilotKit)

長話短說 ---- 在本文中,您將了解如何建立基於 AI 的行銷活動管理應用程式,該應用程式可讓您建立和分析廣告活動,從而使您能夠為您的業務做出正確的決策。 我們將介紹如何: - 使用 Next.js 建立 Web 應用程式, - 使用 CopilotKit 將 AI 助理整合到軟體應用程式中,以及 - 建立特定於操作的人工智慧副駕駛來處理應用程式中的各種任務。 - 建立一名競選經理 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xqpz356qm79t90f1l87.gif) --- CopilotKit:建構應用內人工智慧副駕駛的框架 -------------------------- CopilotKit是一個[開源的AI副駕駛平台](https://github.com/CopilotKit/CopilotKit)。我們可以輕鬆地將強大的人工智慧整合到您的 React 應用程式中。 建造: - ChatBot:上下文感知的應用內聊天機器人,可以在應用程式內執行操作 💬 - CopilotTextArea:人工智慧驅動的文字字段,具有上下文感知自動完成和插入功能📝 - 聯合代理:應用程式內人工智慧代理,可以與您的應用程式和使用者互動🤖 ![https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3 .amazonaws.com%2Fuploads%2Farticles%2Fx3us3vc140aun0dvrdof.gif](https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3us3vc140aun0dvrdof.gif) {% cta https://git.new/devtoarticle1 %} Star CopilotKit ⭐️ {% endcta %} --- 先決條件 ---- 要完全理解本教程,您需要對 React 或 Next.js 有基本的了解。 我們還將利用以下內容: - [Radix UI](https://www.radix-ui.com/) - 用於為應用程式建立可存取的 UI 元件。 - [OpenAI API 金鑰](https://platform.openai.com/api-keys)- 使我們能夠使用 GPT 模型執行各種任務。 - [CopilotKit](https://github.com/CopilotKit/CopilotKit) - 一個開源副駕駛框架,用於建立自訂 AI 聊天機器人、應用程式內 AI 代理程式和文字區域。 --- 專案設定和套件安裝 --------- 首先,透過在終端機中執行以下程式碼片段來建立 Next.js 應用程式: ``` npx create-next-app campaign-manager ``` 選擇您首選的配置設定。在本教學中,我們將使用 TypeScript 和 Next.js App Router。 ![Next.js 應用程式安裝](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xboujt60i6lpoaqgjyap.png) 接下來,將[Heroicons](https://www.npmjs.com/package/@heroicons/react) 、 [Radix UI](https://www.radix-ui.com/)及其原始元件安裝到專案中。 ``` npm install @heroicons/react @radix-ui/react-avatar @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-icons @radix-ui/react-label @radix-ui/react-popover @radix-ui/react-select @radix-ui/react-slot @radix-ui/react-tabs ``` 另外,安裝[Recharts 程式庫](https://recharts.org/en-US)(一個用於建立互動式圖表的 React 程式庫)以及以下實用程式套件: ``` npm install recharts class-variance-authority clsx cmdk date-fns lodash react-day-picker tailwind-merge tailwindcss-animate ``` 最後,安裝[CopilotKit 軟體套件](https://docs.copilotkit.ai/getting-started/quickstart-chatbot)。這些套件使 AI copilot 能夠從 React 狀態檢索資料並在應用程式中做出決策。 ``` npm install @copilotkit/react-ui @copilotkit/react-textarea @copilotkit/react-core @copilotkit/backend ``` 恭喜!您現在已準備好建立應用程式。 --- 使用 Next.js 建立 Campaign Manager 應用程式 ----------------------------------- 在本節中,我將引導您建立活動管理器應用程式的使用者介面。 首先,讓我們進行一些初始設定。 在`src`資料夾中建立一個`components`和`lib`資料夾。 ``` cd src mkdir components lib ``` 在**`lib`**資料夾中,我們將聲明應用程式的靜態類型和預設活動。因此,在**`lib`**資料夾中建立**`data.ts`**和**`types.ts`**檔案。 ``` cd lib touch data.ts type.ts ``` 將下面的程式碼片段複製到`type.ts`檔中。它聲明了活動屬性及其資料類型。 ``` export interface Campaign { id: string; objective?: | "brand-awareness" | "lead-generation" | "sales-conversion" | "website-traffic" | "engagement"; title: string; keywords: string; url: string; headline: string; description: string; budget: number; bidStrategy?: "manual-cpc" | "cpa" | "cpm"; bidAmount?: number; segment?: string; } ``` 為應用程式建立預設的行銷活動清單並將其複製到`data.ts`檔案中。 ``` import { Campaign } from "./types"; export let DEFAULT_CAMPAIGNS: Campaign[] = [ { id: "1", title: "CopilotKit", url: "https://www.copilotkit.ai", headline: "Copilot Kit - The Open-Source Copilot Framework", description: "Build, deploy, and operate fully custom AI Copilots. In-app AI chatbots, AI agents, AI Textareas and more.", budget: 10000, keywords: "AI, chatbot, open-source, copilot, framework", }, { id: "2", title: "EcoHome Essentials", url: "https://www.ecohomeessentials.com", headline: "Sustainable Living Made Easy", description: "Discover our eco-friendly products that make sustainable living effortless. Shop now for green alternatives!", budget: 7500, keywords: "eco-friendly, sustainable, green products, home essentials", }, { id: "3", title: "TechGear Solutions", url: "https://www.techgearsolutions.com", headline: "Innovative Tech for the Modern World", description: "Find the latest gadgets and tech solutions. Upgrade your life with smart technology today!", budget: 12000, keywords: "tech, gadgets, innovative, modern, electronics", }, { id: "4", title: "Global Travels", url: "https://www.globaltravels.com", headline: "Travel the World with Confidence", description: "Experience bespoke travel packages tailored to your dreams. Luxury, adventure, relaxation—your journey starts here.", budget: 20000, keywords: "travel, luxury, adventure, tours, global", }, { id: "5", title: "FreshFit Meals", url: "https://www.freshfitmeals.com", headline: "Healthy Eating, Simplified", description: "Nutritious, delicious meals delivered to your door. Eating well has never been easier or tastier.", budget: 5000, keywords: "healthy, meals, nutrition, delivery, fit", }, ]; ``` 由於我們使用 Radix UI 建立可以使用 TailwindCSS 輕鬆自訂的基本 UI 元件,因此請在**`lib`**資料夾中建立一個**`utils.ts`**文件,並將以下程式碼片段複製到該文件中。 ``` //👉🏻 The lib folder now contains 3 files - data.ts, type.ts, util.ts //👇🏻 Copy the code below into the "lib/util.ts" file. import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } export function randomId() { return Math.random().toString(36).substring(2, 15); } ``` 導航到`components`資料夾並在其中建立其他三個資料夾。 ``` cd components mkdir app dashboard ui ``` `components/app`資料夾將包含應用程式中使用的各種元件,而儀表板資料夾包含某些元素的 UI 元件。 `ui`資料夾包含使用 Radix UI 建立的多個 UI 元素。將[專案儲存庫中的這些元素](https://github.com/CopilotKit/campaign-manager-demo/tree/main/src/components/ui)複製到該資料夾中。 恭喜! `ui`資料夾應包含必要的 UI 元素。現在,我們可以使用它們來建立應用程式中所需的各種元件。 ### 建立應用程式 UI 元件 在這裡,我將引導您完成為應用程式建立使用者介面的過程。 ![應用程式使用者介面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9l4lvv4394gg033oatwq.png) 首先,導航至**`app/page.tsx`**檔案並將以下程式碼片段貼到其中。該文件呈現在**`components/app`**資料夾中聲明的 App 元件。 ``` "use client"; import { App } from "@/components/app/App"; export default function DashboardPage() { return <App />; } ``` 在`components/app`資料夾中建立`App.tsx` 、 `CampaignForm.tsx` 、 `MainNav.tsx`和`UserNav.tsx`檔案。 ``` cd components/app touch App.tsx CampaignForm.tsx MainNav.tsx UserNav.tsx ``` 將下面的程式碼片段複製到`App.tsx`檔案中。 ``` "use client"; import { DEFAULT_CAMPAIGNS } from "@/lib/data"; import { Campaign } from "@/lib/types"; import { randomId } from "@/lib/utils"; import { Dashboard } from "../dashboard/Dashboard"; import { CampaignForm } from "./CampaignForm"; import { useState } from "react"; import _ from "lodash"; export function App() { //👇🏻 default segments const [segments, setSegments] = useState<string[]>([ "Millennials/Female/Urban", "Parents/30s/Suburbs", "Seniors/Female/Rural", "Professionals/40s/Midwest", "Gamers/Male", ]); const [campaigns, setCampaigns] = useState<Campaign[]>( _.cloneDeep(DEFAULT_CAMPAIGNS) ); //👇🏻 updates campaign list function saveCampaign(campaign: Campaign) { //👇🏻 newly created campaign if (campaign.id === "") { campaign.id = randomId(); setCampaigns([campaign, ...campaigns]); } else { //👇🏻 existing campaign - search for the campaign and updates the campaign list const index = campaigns.findIndex((c) => c.id === campaign.id); if (index === -1) { setCampaigns([...campaigns, campaign]); } else { campaigns[index] = campaign; setCampaigns([...campaigns]); } } } const [currentCampaign, setCurrentCampaign] = useState<Campaign | undefined>( undefined ); return ( <div className='relative'> <CampaignForm segments={segments} currentCampaign={currentCampaign} setCurrentCampaign={setCurrentCampaign} saveCampaign={(campaign) => { if (campaign) { saveCampaign(campaign); } setCurrentCampaign(undefined); }} /> <Dashboard campaigns={campaigns} setCurrentCampaign={setCurrentCampaign} segments={segments} setSegments={setSegments} /> </div> ); } ``` - 從上面的程式碼片段來看, - 我為行銷活動建立了預設細分列表,並對已定義的行銷活動列表進行了深層複製。 - `saveCampaign`函數接受行銷活動作為參數。如果行銷活動沒有 ID,則表示它是新建立的,因此會將其新增至行銷活動清單。否則,它會找到該活動並更新其屬性。 - `Dashboard`和`CampaignForm`元件接受細分和行銷活動作為 props。 [Dashboard 元件](https://github.com/CopilotKit/campaign-manager-demo/blob/main/src/components/dashboard/Dashboard.tsx)在儀表板上顯示各種 UI 元素,而[CampaignForm 元件](https://github.com/CopilotKit/campaign-manager-demo/blob/main/src/components/app/CampaignForm.tsx)使用戶能夠在應用程式中建立和保存新的行銷活動。 您也可以使用[GitHub 儲存庫](https://github.com/CopilotKit/campaign-manager-demo/tree/main/src/components)中的程式碼片段來更新儀表板和應用程式元件。 恭喜!您應該有一個有效的 Web 應用程式,可讓使用者查看和建立新的行銷活動。 在接下來的部分中,您將了解如何將 CopilotKit 加入到應用程式中,以根據每個行銷活動的目標和預算進行分析和決策。 ![應用概述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4phyaucli8pdcbe625u4.gif) --- 使用 CopilotKit 透過 AI 分析廣告活動 -------------------------- 在這裡,您將學習如何將人工智慧加入到應用程式中,以幫助您分析行銷活動並做出最佳決策。 在繼續之前,請造訪[OpenAI 開發者平台](https://platform.openai.com/api-keys)並建立一個新的金鑰。 ![取得 OpenAI API 金鑰](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02972pt2aj3kf9l5suqq.png) 建立一個`.env.local`檔案並將新建立的金鑰複製到該檔案中。 ``` OPENAI_API_KEY=<YOUR_OPENAI_SECRET_KEY> OPENAI_MODEL=gpt-4-1106-preview ``` 接下來,您需要為 CopilotKit 建立 API 端點。在 Next.js 應用程式資料夾中,建立一個包含`route.ts`檔案的`api/copilotkit`資料夾。 ``` cd app mkdir api && cd api mkdir copilotkit && cd copilotkit touch route.ts ``` 將下面的程式碼片段複製到`route.ts`檔中。 [CopilotKit 後端](https://docs.copilotkit.ai/reference/CopilotBackend)接受使用者的請求並使用 OpenAI 模型做出決策。 ``` import { CopilotBackend, OpenAIAdapter } from "@copilotkit/backend"; export const runtime = "edge"; export async function POST(req: Request): Promise<Response> { const copilotKit = new CopilotBackend({}); const openaiModel = process.env["OPENAI_MODEL"]; return copilotKit.response(req, new OpenAIAdapter({ model: openaiModel })); } ``` 若要將您的應用程式連接到此 API 端點,請更新`app/page.tsx`文件,如下所示: ``` "use client"; import { App } from "@/components/app/App"; import { CopilotKit } from "@copilotkit/react-core"; import { CopilotSidebar } from "@copilotkit/react-ui"; export default function DashboardPage() { return ( <CopilotKit url='/api/copilotkit/'> <CopilotSidebar instructions='Help the user create and manage ad campaigns.' defaultOpen={true} labels={{ title: "Campaign Manager Copilot", initial: "Hello there! I can help you manage your ad campaigns. What campaign would you like to work on?", }} clickOutsideToClose={false} > <App /> </CopilotSidebar> </CopilotKit> ); } ``` `CopilotKit`元件包裝整個應用程式並接受包含 API 端點連結的`url`屬性。 `CopilotSidebar`元件為應用程式加入了一個聊天機器人側邊欄面板,使我們能夠向 CopilotKit 提供各種指令。 ![將 CopilotKit 加入 Next.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzh8ui253ftzmgtrcksd.gif) ### 如何讓AI副駕駛執行各種動作 CopilotKit 提供了兩個鉤子,使我們能夠處理使用者的請求並插入應用程式狀態: [useCopilotAction](https://docs.copilotkit.ai/reference/useCopilotAction)和[useMakeCopilotReadable](https://docs.copilotkit.ai/reference/useMakeCopilotReadable) 。 `useCopilotAction`掛鉤可讓您定義 CopilotKit 執行的動作。它接受包含以下參數的物件: - name - 操作的名稱。 - 描述 - 操作的描述。 - 參數 - 包含所需參數清單的陣列。 - render - 預設的自訂函數或字串。 - handler - 由操作觸發的可執行函數。 ``` useCopilotAction({ name: "sayHello", description: "Say hello to someone.", parameters: [ { name: "name", type: "string", description: "name of the person to say greet", }, ], render: "Process greeting message...", handler: async ({ name }) => { alert(`Hello, ${name}!`); }, }); ``` `useMakeCopilotReadable`掛鉤向 CopilotKit 提供應用程式狀態。 ``` import { useMakeCopilotReadable } from "@copilotkit/react-core"; const appState = ...; useMakeCopilotReadable(JSON.stringify(appState)); ``` CopilotKit 還允許您為使用者提示提供上下文,使其能夠做出充分且準確的決策。 將`guidance.ts`和`script.ts`加入到專案內的`lib`資料夾中,並將此[指導](https://github.com/CopilotKit/campaign-manager-demo/blob/main/src/lib/guideline.ts)和[腳本建議](https://github.com/CopilotKit/campaign-manager-demo/blob/main/src/lib/script.ts)複製到檔案中,以便 CopilotKit 做出決策。 在應用程式元件中,將當前日期、腳本建議和指導傳遞到 CopilotKit。 ``` import { GUIDELINE } from "@/lib/guideline"; import { SCRIPT_SUGGESTION } from "@/lib/script"; import { useCopilotAction, useMakeCopilotReadable, } from "@copilotkit/react-core"; export function App() { //-- 👉🏻 ...other component functions //👇🏻 Ground the Copilot with domain-specific knowledge for this use-case: marketing campaigns. useMakeCopilotReadable(GUIDELINE); useMakeCopilotReadable(SCRIPT_SUGGESTION); //👇🏻 Provide the Copilot with the current date. useMakeCopilotReadable("Today's date is " + new Date().toDateString()); return ( <div className='relative'> <CampaignForm segments={segments} currentCampaign={currentCampaign} setCurrentCampaign={setCurrentCampaign} saveCampaign={(campaign) => { if (campaign) { saveCampaign(campaign); } setCurrentCampaign(undefined); }} /> <Dashboard campaigns={campaigns} setCurrentCampaign={setCurrentCampaign} segments={segments} setSegments={setSegments} /> </div> ); } ``` 在`App`元件中建立一個 CopilotKit 操作,該操作可在使用者提供此類指令時建立新的活動或編輯現有的活動。 ``` useCopilotAction({ name: "updateCurrentCampaign", description: "Edit an existing campaign or create a new one. To update only a part of a campaign, provide the id of the campaign to edit and the new values only.", parameters: [ { name: "id", description: "The id of the campaign to edit. If empty, a new campaign will be created", type: "string", }, { name: "title", description: "The title of the campaign", type: "string", required: false, }, { name: "keywords", description: "Search keywords for the campaign", type: "string", required: false, }, { name: "url", description: "The URL to link the ad to. Most of the time, the user will provide this value, leave it empty unless asked by the user.", type: "string", required: false, }, { name: "headline", description: "The headline displayed in the ad. This should be a 5-10 words", type: "string", required: false, }, { name: "description", description: "The description displayed in the ad. This should be a short text", type: "string", required: false, }, { name: "budget", description: "The budget of the campaign", type: "number", required: false, }, { name: "objective", description: "The objective of the campaign", type: "string", enum: [ "brand-awareness", "lead-generation", "sales-conversion", "website-traffic", "engagement", ], }, { name: "bidStrategy", description: "The bid strategy of the campaign", type: "string", enum: ["manual-cpc", "cpa", "cpm"], required: false, }, { name: "bidAmount", description: "The bid amount of the campaign", type: "number", required: false, }, { name: "segment", description: "The segment of the campaign", type: "string", required: false, enum: segments, }, ], handler: (campaign) => { const newValue = _.assign( _.cloneDeep(currentCampaign), _.omitBy(campaign, _.isUndefined) ) as Campaign; setCurrentCampaign(newValue); }, render: (props) => { if (props.status === "complete") { return "Campaign updated successfully"; } else { return "Updating campaign"; } }, }); ``` {% 嵌入 https://www.youtube.com/watch?v=gCJpH6Tnj5g %} 新增另一個模擬 API 呼叫的操作,以允許 CopilotKit 從先前建立的活動中檢索歷史資料。 ``` // Provide this component's Copilot with the ability to retrieve historical cost data for certain keywords. // Will be called automatically when needed by the Copilot. useCopilotAction({ name: "retrieveHistoricalData", description: "Retrieve historical data for certain keywords", parameters: [ { name: "keywords", description: "The keywords to retrieve data for", type: "string", }, { name: "type", description: "The type of data to retrieve for the keywords.", type: "string", enum: ["CPM", "CPA", "CPC"], }, ], handler: async ({ type }) => { // fake an API call that retrieves historical data for cost for certain keywords based on campaign type (CPM, CPA, CPC) await new Promise((resolve) => setTimeout(resolve, 2000)); function getRandomValue(min: number, max: number) { return (Math.random() * (max - min) + min).toFixed(2); } if (type == "CPM") { return getRandomValue(0.5, 10); } else if (type == "CPA") { return getRandomValue(5, 100); } else if (type == "CPC") { return getRandomValue(0.2, 2); } }, render: (props) => { // Custom in-chat component rendering. Different components can be rendered based on the status of the action. let label = "Retrieving historical data ..."; if (props.args.type) { label = `Retrieving ${props.args.type} for keywords ...`; } if (props.status === "complete") { label = `Done retrieving ${props.args.type} for keywords.`; } const done = props.status === "complete"; return ( <div className=''> <div className=' w-full relative max-w-xs'> <div className='absolute inset-0 h-full w-full bg-gradient-to-r from-blue-500 to-teal-500 transform scale-[0.80] bg-red-500 rounded-full blur-3xl' /> <div className='relative shadow-xl bg-gray-900 border border-gray-800 px-4 py-8 h-full overflow-hidden rounded-2xl flex flex-col justify-end items-start'> <h1 className='font-bold text-sm text-white mb-4 relative z-50'> {label} </h1> <p className='font-normal text-base text-teal-200 mb-2 relative z-50 whitespace-pre'> {props.args.type && `Historical ${props.args.type}: ${props.result || "..."}`} </p> </div> </div> </div> ); }, }); ``` ![應用程式預覽](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kz3xm63ciq5q3kyooz9s.gif) 恭喜!您已完成本教學的專案。 結論 -- [CopilotKit](https://copilotkit.ai/)是一款令人難以置信的工具,可讓您在幾分鐘內將 AI Copilot 加入到您的產品中。無論您是對人工智慧聊天機器人和助理感興趣,還是對複雜任務的自動化感興趣,CopilotKit 都能讓您輕鬆實現。 如果您需要建立 AI 產品或將 AI 工具整合到您的軟體應用程式中,您應該考慮 CopilotKit。 您可以在 GitHub 上找到本教學的源程式碼: <https://github.com/CopilotKit/campaign-manager-demo> 感謝您的閱讀! --- 原文出處:https://dev.to/copilotkit/build-an-ai-powered-campaign-manager-nextjs-openai-copilotkit-59ii

我用新的程式語言微調了我的模型。你也可以做到! 🚀

我使用 OpenAI ChatGPT-4 一段時間了。 對此我沒什麼好說的。 但有時,這還不夠。 在[Winglang](https://github.com/winglang/wing)中,我們希望使用 OpenAI 和 ChatGPT-4 根據我們的文件回答人們的問題。 您的選擇是: - 使用[OpenAI 助理](https://platform.openai.com/docs/assistants/overview?context=with-streaming)或任何其他基於向量的資料庫 (RAG)。由於 Wing 看起來像 JS,所以效果很好,但仍然有很多錯誤。 - 將整個文件傳遞到上下文視窗的成本非常高。 很快,我們意識到這是行不通的。 是時候舉辦我們自己的法學碩士課程了。 ![問題](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9x9ng6feh6x739djcb0.gif) --- 您的 LLM 資料集 ========== 在訓練模型之前,我們需要建立用於訓練模型的資料。在我們的例子中,是 Winglang 文件。我會做一些非常簡單的事情。 1. 從網站地圖中提取所有 URL,設定 GET 請求並收集內容。 2. 解析它;我們希望將所有 HTML 轉換為可讀內容。 3. 使用 ChatGPT 4 執行它,將內容轉換為 CSV 作為資料集。 它應該是這樣的: ![法學碩士資料集](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2xq8lm4b31k8pop4gmc.png) 完成後,儲存包含一列名為`text`的 CSV 並新增問題和答案。我們稍後會用到它。它應該看起來像這樣: ``` text <s>[INST]How to define a variable in Winglang[/INST] let a = 'Hello';</s> <s>[INST]How to create a new lambda[/INST] bring cloud; let func = new cloud.Function(inflight () => { log('Hello from the cloud!'); });</s> ``` 將其保存在電腦上名為`data`新資料夾中。 --- Autotrain,您的模型 ============== 我的電腦很弱,所以我決定使用更小的模型 - 7b 參數: `mistralai/Mistral-7B-v0.1` 訓練模型的方法有數百萬種。我們將使用 Huggingface Autotrain。我們將使用他們的 CLI,而不執行任何 Python 程式碼🚀 當您使用 Huggingface 的 Autotrain 時,您可以在電腦上訓練它(這裡是我的方法)或在他們的伺服器上訓練它(付費)並訓練更大的模型。 我的舊 Macbook Pro M1 2021 沒有 GPU。 讓我們安裝自動訓練。 ``` pip install -U autotrain-advanced autotrain setup > setup_logs.txt ``` 然後,我們需要做的就是執行 autotrain 指令: ``` autotrain llm \ --train \ --model "mistralai/Mistral-7B-Instruct-v0.2" \ --project-name "autotrain-wing" \ --data-path data/ \ --text-column text \ --lr "0.0002" \ --batch-size "1" \ --epochs "3" \ --block-size "1024" \ --warmup-ratio "0.1" \ --lora-r "16" \ --lora-alpha "32" \ --lora-dropout "0.05" \ --weight-decay "0.01" \ --gradient-accumulation "4" \ --quantization "int4" \ --mixed-precision "fp16" \ --peft ``` 完成後,您將擁有一個名為“autotrain-wing”的新目錄,其中包含新的微調模型🚀 --- 玩模型 --- 要使用模型,請先執行: ``` pip install transformers torch ``` 完成後,使用以下程式碼建立一個名為 invoke.py 的新 Python 檔案: ``` from transformers import pipeline # Path to your local model directory model_path = "./autotrain-wing" # Load the model and tokenizer from the local directory classifier = pipeline("text-classification", model=model_path, tokenizer=model_path) # Example text to classify text = "Example text to classify" result = classifier(text) print(result) ``` 然後您可以透過執行 CLI 命令來執行它: ``` python invoke.py ``` 你就完成了🚀 --- 繼續攻讀法學碩士 -------- 我仍在學習法學碩士。 我意識到的一件事是追蹤模型的變化並不容易。 你不能真正將它與 Git 一起使用,因為模型可以達到非常大的大小 &gt; 100 GB;這沒有多大意義——git 不能很好地處理它。 更好的方法是使用名為[KitOps 的](https://github.com/jozu-ai/kitops/)工具。 我認為它很快就會成為法學碩士世界的標準,所以請確保你給這個庫加註星標,以便以後可以使用它。 1. 下載最新的[KitOps 版本](https://github.com/jozu-ai/kitops/releases/tag/v0.1.3)並[安裝它](https://kitops.ml/docs/cli/installation.html)。 2. 轉到模型資料夾並執行命令來打包您的 LLM: ``` kit pack . ``` 3. 您也可以透過執行將其推送到 Docker hub ``` kit pack . -t [your registry address]/[your repository name]/mymodelkit:latest ``` > 💡 要了解如何使用 DockerHub,[請檢查此](https://kitops.ml/docs/quick-start.html) {% cta https://github.com/jozu-ai/kitops %}⭐️ Star KitOps,以便您稍後可以再次找到它⭐️{% endcta %} [![星庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/362tc5831i5ozbsau2o3.png)](https://github.com/jozu-ai/kitops) --- 我建立了一個新的 YouTube 頻道,主要是關於開源行銷:) (例如如何獲得星星、叉子和客戶端) 如果您對此感興趣,請隨時在這裡訂閱: https://www.youtube.com/@nevo-david?sub\_confirmation=1 --- 原文出處:https://dev.to/github20k/i-fine-tuned-my-model-on-a-new-programming-language-you-can-do-it-too-449

🚀 21 個將你的開發技能帶上月球的工具 🌝

我見過數百種人工智慧工具,其中許多正在改變世界。 作為開發人員,總是有很多事情需要學習,因此專注於節省時間來處理重要的事情非常重要。 我將介紹 21 個供開發人員使用的工具,它們可以讓您的生活更輕鬆,特別是在開發人員體驗方面。 相信我,這份清單會讓你大吃一驚! 我們開始做吧。 --- 1. [Taipy](https://github.com/Avaiga/taipy) - 將資料和人工智慧演算法整合到生產就緒的 Web 應用程式中。 ---------------------------------------------------------------------------- ![打字](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd10iiofzmt4or4db6ej.png) Taipy 是一個開源 Python 庫,可用於輕鬆的端到端應用程式開發,具有假設分析、智慧管道執行、內建調度和部署工具。 我相信你們大多數人都不明白 Taipy 用於為基於 Python 的應用程式建立 GUI 介面並改進資料流管理。 關鍵是性能,而 Taipy 是最佳選擇。 雖然 Streamlit 是一種流行的工具,但在處理大型資料集時,其效能可能會顯著下降,這使得它在生產級使用上不切實際。 另一方面,Taipy 在不犧牲性能的情況下提供了簡單性和易用性。透過嘗試 Taipy,您將親身體驗其用戶友好的介面和高效的資料處理。 ![大資料支持](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnvk0tozn0lgj083rzcb.gif) Taipy 有許多整合選項,可以輕鬆地與領先的資料平台連接。 ![整合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7yv31uir3erina587zp8.png) 開始使用以下命令。 ``` pip install taipy ``` 我們來談談最新的[Taipy v3.1 版本](https://docs.taipy.io/en/latest/relnotes/)。 最新版本使得在 Taipy 的多功能零件物件中可視化任何 HTML 或 Python 物件成為可能。 這意味著[Folium](https://python-visualization.github.io/folium/latest/) 、 [Bokeh](https://bokeh.org/) 、 [Vega-Altair](https://altair-viz.github.io/)和[Matplotlib](https://matplotlib.org/)等程式庫現在可用於視覺化。 這也帶來了對[Plotly python](https://plotly.com/python/)的原生支持,使繪製圖表變得更加容易。 他們還使用分散式運算提高了效能,但最好的部分是 Taipy,它的所有依賴項現在都與 Python 3.12 完全相容,因此您可以在使用 Taipy 進行專案的同時使用最新的工具和程式庫。 您可以閱讀[文件](https://docs.taipy.io/en/latest/)。 ![用例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xdvnbejf9aivxmqsd3hx.png) 另一個有用的事情是,Taipy 團隊提供了一個名為[Taipy Studio](https://docs.taipy.io/en/latest/manuals/studio/)的 VSCode 擴充功能來加速 Taipy 應用程式的建置。 ![太皮工作室](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kc1umm5hcxes0ydbuspb.png) 您也可以使用 Taipy 雲端部署應用程式。 如果您想閱讀部落格來了解程式碼庫結構,您可以閱讀 HuggingFace[的使用 Taipy 在 Python 中為您的 LLM 建立 Web 介面](https://huggingface.co/blog/Alex1337/create-a-web-interface-for-your-llm-in-python)。 嘗試新技術通常很困難,但 Taipy 提供了[10 多個演示教程,](https://docs.taipy.io/en/release-3.1/gallery/)其中包含程式碼和適當的文件供您遵循。 ![示範](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wigid2aokt6spkkoivr.png) 例如,一些演示範例和專案想法: - [即時污染儀表板](https://docs.taipy.io/en/release-3.0/knowledge_base/demos/pollution_sensors/) 使用工廠周圍的感測器測量空氣品質的用例,展示 Taipy 儀表板流資料的能力。檢查[GitHub 儲存庫](https://github.com/Avaiga/demo-realtime-pollution)。 - [詐欺辨識](https://docs.taipy.io/en/release-3.0/knowledge_base/demos/fraud_detection/) Taipy 應用程式可分析信用卡交易以偵測詐欺行為。檢查[GitHub 儲存庫](https://github.com/Avaiga/demo-fraud-detection)。 - [新冠儀表板](https://docs.taipy.io/en/release-3.0/knowledge_base/demos/covid_dashboard/) 這使用 2020 年的 Covid 資料集。還有一個預測頁面來預測傷亡人數。檢查[GitHub 儲存庫](https://github.com/Avaiga/demo-covid-dashboard)。 - [建立 LLM 聊天機器人](https://docs.taipy.io/en/release-3.0/knowledge_base/demos/chatbot/) 該演示展示了 Taipy 使最終用戶能夠使用 LLM 執行推理的能力。在這裡,我們使用 GPT-3 建立一個聊天機器人,並將對話顯示在互動式聊天介面中。您可以輕鬆更改程式碼以使用任何其他 API 或模型。檢查[GitHub 儲存庫](https://github.com/Avaiga/demo-chatbot)。 - [即時人臉辨識](https://docs.taipy.io/en/release-3.0/knowledge_base/demos/face_recognition/) 該演示將人臉辨識無縫整合到我們的平台中,使用網路攝影機提供使用者友好的即時人臉偵測體驗。檢查[GitHub 儲存庫](https://github.com/Avaiga/demo-face-recognition)。 這些用例非常驚人,所以一定要檢查一下。 Taipy 在 GitHub 上有 8.2k+ Stars,並且處於`v3.1`版本,因此它們正在不斷改進。 {% cta https://github.com/Avaiga/taipy %} Star Taipy ⭐️ {% endcta %} --- 2. [DevToys](https://github.com/DevToys-app/DevToys) - 開發者的瑞士軍刀。 ---------------------------------------------------------------- ![開發玩具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zfl1wjr01fdvca6wxbi.png) DevToys 協助完成日常開發任務,例如格式化 JSON、比較文字和測試 RegExp。 這樣,就無需使用不可信的網站來處理您的資料執行簡單的任務。透過智慧型偵測,DevToys 可以偵測用於複製到 Windows 剪貼簿的資料的最佳工具。 緊湊的覆蓋範圍讓您可以保持應用程式較小並位於其他視窗之上。最好的部分是可以同時使用應用程式的多個實例。 我可以肯定地說,開發人員甚至不知道這個很棒的專案。 最後是一款專為 Windows 生態系統設計的軟體。哈哈! ![工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i7wd60jsgdb5tx2t2adi.png) 他們提供的一些工具是: > 轉換器 - JSON &lt;&gt; YAML - 時間戳 - 數基數 - 規劃任務解析器 ![轉換器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8x784fx53x6ia02zal0.png) > 編碼器/解碼器 - 超文本標記語言 - 網址 - Base64 文字與圖片 - 壓縮包 - 智威湯遜解碼器 ![編碼器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73ts4x1vtcy4yswsmytw.png) > 格式化程式 - JSON - SQL - XML ![XML](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5dc8ko2baywta82ymq5.png) > 發電機 - 哈希(MD5、SHA1、SHA256、SHA512) - UUID 1 和 4 - 洛雷姆·伊普蘇姆 - 校驗和 ![發電機](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwsq8xig6jf69wr99iuv.png) > 文字 - 逃脫/逃脫 - 檢驗員和箱子轉換器 - 正規表示式測試器 - 文字比較 - XML驗證器 - 降價預覽 ![MD預覽](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcbkse1i5324qg3xu1yd.png) ![文字差異](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlqqib4fcjimc03pdrwr.png) > 形象的 - 色盲模擬器 - 顏色選擇器和對比度 - PNG / JPEG 壓縮器 - 影像轉換器 ![圖形工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/631upekcqzh62xyrdjwt.png) 我不了解你,但我不會錯過這個! 您可以閱讀[如何執行 DevToys](https://github.com/DevToys-app/DevToys?tab=readme-ov-file#how-to-run-devtoys) 。 關於許可證的註解。 DevToys 使用的授權允許將應用程式作為試用軟體或共享軟體重新分發而無需進行任何更改。然而,作者 Etienne BAUDOUX 和 BenjaminT 不希望你這樣做。如果您認為自己有充分的理由這樣做,請先與我們聯絡討論。 他們在 GitHub 上有 23k Stars,並且使用 C#。 {% cta https://github.com/DevToys-app/DevToys %} 明星 DevToys ⭐️ {% endcta %} --- 3. [Pieces](https://github.com/pieces-app) - 您的工作流程副駕駛。 ------------------------------------------------------- ![件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qf2qgqtpv78fxw5guqm5.png) Pieces 是一款支援人工智慧的生產力工具,旨在透過智慧程式碼片段管理、情境化副駕駛互動和主動呈現有用材料來幫助開發人員管理混亂的工作流程。 它最大限度地減少了上下文切換、簡化了工作流程並提升了整體開發體驗,同時透過完全離線的 AI 方法維護了工作的隱私和安全性。太棒了:D ![整合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2ro3rcwnqp4qrmv5e8s.png) 它與您最喜歡的工具無縫集成,以簡化、理解和提升您的編碼流程。 它具有比表面上看到的更令人興奮的功能。 - 它可以透過閃電般快速的搜尋體驗找到您需要的材料,讓您根據您的喜好透過自然語言、程式碼、標籤和其他語義進行查詢。可以放心地說“您的個人離線谷歌”。 - Pieces 使用 OCR 和 Edge-ML 升級螢幕截圖,以提取程式碼並修復無效字元。因此,您可以獲得極其準確的程式碼提取和深度元資料豐富。 您可以查看 Pieces 可用[功能的完整清單](https://pieces.app/features)。 您可以閱讀[文件](https://docs.pieces.app/)並存取[網站](https://pieces.app/)。 他們為 Pieces OS 用戶端提供了一系列 SDK 選項,包括[TypeScript](https://github.com/pieces-app/pieces-os-client-sdk-for-typescript) 、 [Kotlin](https://github.com/pieces-app/pieces-os-client-sdk-for-kotlin) 、 [Python](https://github.com/pieces-app/pieces-os-client-sdk-for-python)和[Dart](https://github.com/pieces-app/pieces-os-client-sdk-for-dart) 。 就開源流行度而言,他們仍然是新的,但他們的社群是迄今為止我見過的最好的社群之一。加入他們,成為 Pieces 的一部分! {% cta https://github.com/pieces-app/ %} 星星碎片 ⭐️ {% endcta %} --- 4. [Infisical-](https://github.com/Infisical/infisical)秘密管理平台。 -------------------------------------------------------------- ![內部的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrolzjdnkky1r694h9av.png) Infisical 是一個開源秘密管理平台,團隊可以用它來集中 API 金鑰、資料庫憑證和設定等秘密。 他們讓每個人(而不僅僅是安全團隊)都可以更輕鬆地進行秘密管理,這意味著從頭開始重新設計整個開發人員體驗。 就我個人而言,我不介意使用 .env 文件,因為我並不特別謹慎。不過,您可以閱讀[立即停止使用 .env 檔案!](https://dev.to/gregorygaines/stop-using-env-files-now-kp0)由格雷戈里來理解。 他們提供了四種 SDK,分別用於<a href="">Node.js</a> 、 <a href="">Python</a> 、 <a href="">Java</a>和<a href="">.Net</a> 。您可以自行託管或使用他們的雲端。 開始使用以下 npm 指令。 ``` npm install @infisical/sdk ``` 這是使用入門 (Node.js SDK) 的方法。 ``` import { InfisicalClient, LogLevel } from "@infisical/sdk"; const client = new InfisicalClient({ clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET", logLevel: LogLevel.Error }); const secrets = await client.listSecrets({ environment: "dev", projectId: "PROJECT_ID", path: "/foo/bar/", includeImports: false }); ``` ![內部](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3eu288l470du91b66pd.png) Infisical 還提供了一組工具來自動防止 git 歷史記錄的秘密洩露。可以使用預提交掛鉤或透過與 GitHub 等平台直接整合在 Infisical CLI 層級上設定此功能。 您可以閱讀[文件](https://infisical.com/docs/documentation/getting-started/introduction)並檢查如何[安裝 CLI](https://infisical.com/docs/cli/overview) ,這是使用它的最佳方式。 Infisical 還可用於將機密注入 Kubernetes 叢集和自動部署,以便應用程式使用最新的機密。有很多整合選項可用。 ![內部](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5x0tvt5ycaiqhggv6wml.png) 在使用整個原始程式碼之前一定要檢查他們的[許可證](https://github.com/Infisical/infisical/blob/main/LICENSE),因為他們有一些受 MIT Expat 保護的企業級程式碼,但不用擔心,大部分程式碼都是免費使用的。 他們在 GitHub 上擁有超過 11k 顆星星,並且發布了超過 125 個版本,因此他們正在不斷發展。另外,Infiscial CLI 的安裝次數超過 540 萬次,因此非常值得信賴。 {% cta https://github.com/Infisical/infisical %} 明星 Infisical ⭐️ {% endcta %} --- 5. [Mintlify](https://github.com/mintlify/writer) - 在建置時出現的文件。 -------------------------------------------------------------- ![精簡](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvk07kmn8p48cpssogov.png) Mintlify 是一款由人工智慧驅動的文件編寫器,您只需 1 秒鐘即可編寫程式碼文件 :D 幾個月前我發現了 Mintlify,從那時起我就一直是它的粉絲。我見過很多公司使用它,甚至我使用我的商務電子郵件產生了完整的文件,結果證明這是非常簡單和體面的。如果您需要詳細的文件,Mintlify 就是解決方案。 主要用例是根據我們將在此處討論的程式碼產生文件。當您編寫程式碼時,它會自動記錄程式碼,以便其他人更容易跟上。 您可以安裝[VSCode 擴充功能](https://marketplace.visualstudio.com/items?itemName=mintlify.document)或將其安裝在[IntelliJ](https://plugins.jetbrains.com/plugin/18606-mintlify-doc-writer)上。 您只需突出顯示程式碼或將遊標放在要記錄的行上。然後點選「編寫文件」按鈕(或按 ⌘ + 。) 您可以閱讀[文件](https://github.com/mintlify/writer?tab=readme-ov-file#%EF%B8%8F-mintlify-writer)和[安全指南](https://writer.mintlify.com/security)。 如果您更喜歡教程,那麼您可以觀看[Mintlify 的工作原理](https://www.loom.com/embed/3dbfcd7e0e1b47519d957746e05bf0f4)。它支援 10 多種程式語言,並支援許多文件字串格式,例如 JSDoc、reST、NumPy 等。 順便說一句,他們的網站連結是[writer.mintlify.com](https://writer.mintlify.com/) ;回購協議中目前的似乎是錯誤的。 Mintlify 是一個方便的工具,用於記錄程式碼,這是每個開發人員都應該做的事情。它使其他人更容易有效地理解您的程式碼。 它在 GitHub 上有大約 2.5k 顆星,基於 TypeScript 建置,受到許多開發人員的喜愛。 {% cta https://github.com/mintlify/writer %} Star Mintlify ⭐️ {% endcta %} --- 6. [Replexica](https://github.com/replexica/replexica) - 用於 React 的 AI 支援的 i18n 工具包。 ------------------------------------------------------------------------------------ ![反射](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htgshukxy927iy37ui33.png) 在地化方面的困難是真實存在的,因此人工智慧的幫助絕對是一個很酷的概念。 Replexica 是 React 的 i18n 工具包,可快速發布多語言應用程式。它不需要將文字提取到 JSON 檔案中,並使用 AI 支援的 API 進行內容處理。 它有以下兩個部分: 1. Replexica Compiler - React 的開源編譯器插件。 2. Replexica API - 雲端中的 i18n API,使用 LLM 執行翻譯。 (基於使用情況,它有免費套餐) 支援的一些 i18n 格式包括: 1. 無 JSON 的 Replexica 編譯器格式。 2. Markdown 內容的 .md 檔案。 3. 基於舊版 JSON 和 YAML 的格式。 當他們達到 500 星時,他們也在 DEV 上發布了官方公告。我是第一批讀者之一(少於 3 個反應)。 它們涵蓋了很多內容,因此您應該閱讀 Max 的[《We Got 500 Stars What Next》](https://dev.to/maxprilutskiy/we-got-500-github-stars-whats-next-2njc) 。 為了給出 Replexica 背後的總體思路,這是基本 Next.js 應用程式所需的唯一更改,以使其支援多語言。 開始使用以下 npm 指令。 ``` // install pnpm add replexica @replexica/react @replexica/compiler // login to Replexica API. pnpm replexica auth --login ``` 您可以這樣使用它。 ``` // next.config.mjs // Import Replexica Compiler import replexica from '@replexica/compiler'; /** @type {import('next').NextConfig} */ const nextConfig = {}; // Define Replexica configuration /** @type {import('@replexica/compiler').ReplexicaConfig} */ const replexicaConfig = { locale: { source: 'en', targets: ['es'], }, }; // Wrap Next.js config with Replexica Compiler export default replexica.next( replexicaConfig, nextConfig, ); ``` 您可以閱讀如何[開始使用](https://github.com/replexica/replexica/blob/main/getting-started.md)以及清楚記錄的有關[幕後使用內容的](https://github.com/replexica/replexica?tab=readme-ov-file#whats-under-the-hood)內容。 Replexica 編譯器支援 Next.js App Router,Replexica API 支援英文🇺🇸和西班牙文🇪🇸。他們計劃接下來發布 Next.js Pages Router + 法語🇫🇷語言支援! 他們在 GitHub 上擁有 740 多個 Star,並且基於 TypeScript 建置。您應該密切關注該專案以獲得進一步進展! {% cta https://github.com/replexica/replexica %} Star Replexica ⭐️ {% endcta %} --- 7. [Flowise](https://github.com/FlowiseAI/Flowise) - 拖放 UI 來建立您的客製化 LLM 流程。 --------------------------------------------------------------------------- ![弗洛伊薩伊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5bp43nil764fhe4a05z.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://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahk2ovjrpq1qk3r5pfot.png) 您可以閱讀[文件](https://docs.flowiseai.com/)。 ![流程化人工智慧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trkltpn5lk1y1pte0smd.png) 雲端主機不可用,因此您必須使用這些[說明](https://github.com/FlowiseAI/Flowise?tab=readme-ov-file#-self-host)自行託管。 讓我們探討一些用例: - 假設您有一個網站(可以是商店、電子商務網站或部落格),並且您希望廢棄該網站的所有相關連結,並讓法學碩士回答您網站上的任何問題。您可以按照此[逐步教學](https://docs.flowiseai.com/use-cases/web-scrape-qna)來了解如何實現相同的目標。 ![刮刀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e91sz2mga5wvc0x2hp2g.png) - 您還可以建立一個自訂工具,該工具將能夠呼叫 Webhook 端點並將必要的參數傳遞到 Webhook 主體中。請依照本[指南](https://docs.flowiseai.com/use-cases/webhook-tool)使用 Make.com 建立 Webhook 工作流程。 ![網路鉤子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckyivo9dvue461jc9pv4.png) 還有許多其他用例,例如建立 SQL QnA 或與 API 互動。 FlowiseAI 在 GitHub 上擁有超過 27,500 個 Star,並擁有超過 10,000 個分叉,因此具有良好的整體比率。 {% cta https://github.com/FlowiseAI/Flowise %} 明星 Flowise ⭐️ {% endcta %} --- 8. [Hexo](https://github.com/hexojs/hexo) - 一個快速、簡單且功能強大的部落格框架。 --------------------------------------------------------------- ![六角形](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vos07fyydiupqqplo2s.png) 大多數開發人員更喜歡自己的博客,如果您也是如此。 Hexo 可能是你不知道的工具。 Hexo 支援許多功能,例如超快的生成速度,支援 GitHub Flavored Markdown 和大多數 Octopress 插件,提供對 GitHub Pages、Heroku 等的一命令部署,以及可實現無限擴展性的強大 API 和數百個主題和插件。 這意味著您可以用 Markdown(或其他標記語言)編寫帖子,Hexo 在幾秒鐘內生成具有漂亮主題的靜態檔案。 開始使用以下 npm 指令。 ``` npm install hexo-cli -g ``` 您可以這樣使用它。 ``` // Setup your blog hexo init blog // Start the server hexo server // Create a new post hexo new "Hello Hexo" ``` 您可以閱讀[文件](https://hexo.io/docs/),查看 Hexo 提供的所有[400 多個外掛程式](https://hexo.io/plugins/)和[主題集](https://hexo.io/themes/)。據我所知,這些外掛程式支援廣泛的用例,例如 Hexo 的 Ansible 部署器外掛程式。 您可以查看有關在[Hexo 上編寫和組織內容的](https://www.youtube.com/watch?v=AIqBubK6ZLc&t=6s)YouTube 教學。 Hexo 在 GitHub 上擁有超過 38,000 顆星,並被 GitHub 上超過 125,000 名開發者使用。它們位於`v7`版本中,解壓縮後大小為`629 kB` 。 {% cta https://github.com/hexojs/hexo %} Star Hexo ⭐️ {% endcta %} --- 9.[螢幕截圖到程式碼](https://github.com/abi/screenshot-to-code)- 放入螢幕截圖並將其轉換為乾淨的程式碼。 --------------------------------------------------------------------------- ![截圖到程式碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5akiyz5telxqqsj32ftu.png) 這個開源專案廣泛流行,但許多開發人員仍然不了解它。它可以幫助您以 10 倍的速度建立使用者介面。 這是一個簡單的工具,可以使用 AI 將螢幕截圖、模型和 Figma 設計轉換為乾淨、實用的程式碼。 該應用程式有一個 React/Vite 前端和一個 FastAPI 後端。如果您想使用 Claude Sonnet 或獲得實驗視訊支持,您將需要一個能夠存取 GPT-4 Vision API 的 OpenAI API 金鑰或一個 Anthropic 金鑰。您可以閱讀[指南](https://github.com/abi/screenshot-to-code?tab=readme-ov-file#-getting-started)來開始。 您可以在託管版本上[即時試用](https://screenshottocode.com/),並觀看 wiki 上提供的[一系列演示影片](https://github.com/abi/screenshot-to-code/wiki/Screen-Recording-to-Code)。 他們在 GitHub 上擁有超過 47k 顆星星,並支援許多技術堆疊,例如 React 和 Vue,以及不錯的 AI 模型,例如 GPT-4 Vision、Claude 3 Sonnet 和 DALL-E 3。 {% cta https://github.com/abi/screenshot-to-code %} 將螢幕截圖轉為程式碼 ⭐️ {% endcta %} --- 10. [Appsmith](https://github.com/appsmithorg/appsmith) - 建立管理面板、內部工具和儀表板的平台。 ----------------------------------------------------------------------------- ![應用史密斯](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rt7s0r3wz2leec83cl17.png) 管理面板和儀表板是任何軟體創意(在大多數情況下)的一些常見部分,我嘗試從頭開始建立它,這會帶來很多痛苦和不必要的辛苦工作。 您可能已經看到組織建立了內部應用程式,例如儀表板、資料庫 GUI、管理面板、批准應用程式、客戶支援儀表板等,以幫助其團隊執行日常操作。正如我所說,Appsmith 是一個開源工具,可以實現這些內部應用程式的快速開發。 首先,請觀看這個[YouTube 影片](https://www.youtube.com/watch?v=NnaJdA1A11s),該影片在 100 秒內解釋了 Appsmith。 {% 嵌入 https://www.youtube.com/watch?v=NnaJdA1A11s %} 他們提供拖放小部件來建立 UI。 您可以使用 45 多個可自訂的小工具在幾分鐘內建立漂亮的響應式 UI,而無需編寫一行 HTML/CSS。尋找[小部件的完整清單](https://www.appsmith.com/widgets)。 ![按鈕點擊小工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqpnnslvsvjl4gifseon.png) ![驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/489fly7tvknz2uv2mgei.png) Appsmith 幾乎可以在 GUI 上的小部件屬性、事件偵聽器、查詢和其他設定內的任何位置編寫 JavaScript 程式碼。 Appsmith 支援在`{{ }}`內編寫單行程式碼,並將括號之間編寫的任何內容解釋為 JavaScript 表達式。 ``` /*Filter the data array received from a query*/ {{ QueryName.data.filter((row) => row.id > 5 ) }} or {{ storeValue("userID", 42); console.log(appsmith.store.userID); showAlert("userID saved"); }} ``` 您需要使用立即呼叫函數表達式(IIFE)來編寫多行。 例如,無效程式碼和有效程式碼。 ``` // invalid code /*Call a query to fetch the results and filter the data*/ {{ const array = QueryName.data; const filterArray = array.filter((row) => row.id > 5); return filterArray; }} /* Check the selected option and return the value*/ {{ if (Dropdown.selectedOptionValue === "1") { return "Option 1"; } else { return "Option 2"; } }} // valid code /* Call a query and then manipulate its result */ {{ (function() { const array = QueryName.data; const filterArray = array.filter((row) => row.id > 5); return filterArray; })() }} /* Verify the selected option and return the value*/ {{ (function() { if (Dropdown.selectedOptionValue === "1") { return "Option 1"; } else { return "Option 2"; } })() }} ``` 您可以透過幾個簡單的步驟建立從簡單的 CRUD 應用程式到複雜的多步驟工作流程的任何內容: 1. 與資料庫或 API 整合。 Appsmith 支援最受歡迎的資料庫和 REST API。 2. 使用內建小工具建立您的應用程式佈局。 3. 在編輯器中的任何位置使用查詢和 JavaScript 來表達您的業務邏輯。 4. Appsmith 支援使用 Git 進行版本控制,以使用分支來協作建立應用程式來追蹤和回滾變更。部署應用程式並分享:) ![應用史密斯](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yltcrmuzwdoydrwyqjpp.png) 您可以閱讀[文件](https://docs.appsmith.com/)和[操作指南](https://docs.appsmith.com/connect-data/how-to-guides),例如如何將其連接到本機資料來源或\[如何與第三方工具整合\](與第三方工具整合)。 您可以自行託管或使用雲端。他們還提供[20 多個模板](https://www.appsmith.com/templates),以便您可以快速入門。一些有用的是: - [維修訂單管理](https://www.appsmith.com/template/Maintenance-Order-Management) - [加密即時追蹤器](https://www.appsmith.com/template/crypto-live-tracker) - [內容管理系統](https://www.appsmith.com/template/content-management-system) - [WhatsApp 信使](https://www.appsmith.com/template/whatsapp-messenger) Appsmith 在 GitHub 上擁有超過 31,000 顆星,發布了 200 多個版本。 {% cta https://github.com/appsmithorg/appsmith %} Star Appsmith ⭐️ {% endcta %} --- 11. [BlockNote](https://github.com/TypeCellOS/BlockNote) - 基於區塊(Notion 樣式)且可擴充的富文本編輯器。 -------------------------------------------------------------------------------------- ![區塊註釋](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eddx8cld0g492w3a8fjh.png) 人們常說,除非您正在學習新東西,否則不要重新發明輪子。 Blocknote 是開源的 Block 為基礎的 React 富文本編輯器。您可以輕鬆地將現代文字編輯體驗加入到您的應用程式中。 Blocknote 建構在 Prosemirror 和 Tiptap 之上。 它們有很多功能,如下所示。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9kd6xnkg9fa5j29frot.png) ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ezuz7ywh6vefixmpeyzk.png) 您可以輕鬆自訂內建 UI 元件,或建立自訂區塊、內聯內容和樣式。如果您想更進一步,您可以使用額外的 Prosemirror 或 TipTap 外掛程式來擴充核心編輯器。 其他庫雖然功能強大,但通常具有相當陡峭的學習曲線,並且要求您自訂編輯器的每個細節。這可能需要數月的專門工作。 相反,BlockNote 只需最少的設定即可提供出色的體驗,包括現成的動畫 UI。 開始使用以下 npm 指令。 ``` npm install @blocknote/core @blocknote/react ``` 您可以這樣使用它。透過`useCreateBlockNote`鉤子,我們可以建立一個新的編輯器實例,然後使用`theBlockNoteView`元件來渲染它。 `@blocknote/react/style.css`也被匯入來新增編輯器的預設樣式和 BlockNote 匯出的 Inter 字體(可選)。 ``` import "@blocknote/core/fonts/inter.css"; import { BlockNoteView, useCreateBlockNote } from "@blocknote/react"; import "@blocknote/react/style.css"; export default function App() { // Creates a new editor instance. const editor = useCreateBlockNote(); // Renders the editor instance using a React component. return <BlockNoteView editor={editor} />; } ``` 您可以閱讀可用的[文件](https://www.blocknotejs.org/docs)和[ui 元件](https://www.blocknotejs.org/docs/ui-components)。 您應該嘗試一下,特別是因為它包含廣泛的功能,例如「斜線」選單、流暢的動畫以及建立即時協作應用程式的潛力。 ![削減](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0i7ob8nrhpl7r70k6527.png) 斜線選單 ![即時協作](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id22qol6y0838zgwad3y.png) 即時協作 ![格式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d8maems8tfhtehw9lkol.png) 格式選單 他們還提供了[20 多個範例](https://www.blocknotejs.org/examples)以及預覽和程式碼,您可以使用它們來快速跟進。 ![例子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4uillknk0ogkcvpula7b.png) Blocknote 在 GitHub 上擁有超過 5,000 顆星,並有超過 1,500 名開發者在使用。 {% cta https://github.com/TypeCellOS/BlockNote %} 星 BlockNote ⭐️ {% endcta %} --- 12. [CopilotKit](https://github.com/CopilotKit/CopilotKit) - 在數小時內為您的產品提供 AI Copilot。 ------------------------------------------------------------------------------------- ![副駕駛套件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzuxjfog2ldam3csrl62.png) 將 AI 功能整合到 React 中是很困難的,這就是 Copilot 的用武之地。一個簡單快速的解決方案,可將可投入生產的 Copilot 整合到任何產品中! 您可以使用兩個 React 元件將關鍵 AI 功能整合到 React 應用程式中。它們還提供內建(完全可自訂)Copilot 原生 UX 元件,例如`<CopilotKit />` 、 `<CopilotPopup />` 、 `<CopilotSidebar />` 、 `<CopilotTextarea />` 。 開始使用以下 npm 指令。 ``` npm i @copilotkit/react-core @copilotkit/react-ui ``` Copilot Portal 是 CopilotKit 提供的元件之一,CopilotKit 是一個應用程式內人工智慧聊天機器人,可查看目前應用狀態並在應用程式內採取操作。它透過插件與應用程式前端和後端以及第三方服務進行通訊。 這就是整合聊天機器人的方法。 `CopilotKit`必須包裝與 CopilotKit 互動的所有元件。建議您也開始使用`CopilotSidebar` (您可以稍後切換到不同的 UI 提供者)。 ``` "use client"; import { CopilotKit } from "@copilotkit/react-core"; import { CopilotSidebar } from "@copilotkit/react-ui"; import "@copilotkit/react-ui/styles.css"; export default function RootLayout({children}) { return ( <CopilotKit url="/path_to_copilotkit_endpoint/see_below"> <CopilotSidebar> {children} </CopilotSidebar> </CopilotKit> ); } ``` 您可以使用此[快速入門指南](https://docs.copilotkit.ai/getting-started/quickstart-backend)設定 Copilot 後端端點。 之後,您可以讓 Copilot 採取行動。您可以閱讀如何提供[外部上下文](https://docs.copilotkit.ai/getting-started/quickstart-chatbot#provide-context)。您可以使用`useMakeCopilotReadable`和`useMakeCopilotDocumentReadable`反應掛鉤來執行此操作。 ``` "use client"; import { useMakeCopilotActionable } from '@copilotkit/react-core'; // Let the copilot take action on behalf of the user. useMakeCopilotActionable( { name: "setEmployeesAsSelected", // no spaces allowed in the function name description: "Set the given employees as 'selected'", argumentAnnotations: [ { name: "employeeIds", type: "array", items: { type: "string" } description: "The IDs of employees to set as selected", required: true } ], implementation: async (employeeIds) => setEmployeesAsSelected(employeeIds), }, [] ); ``` 您可以閱讀[文件](https://docs.copilotkit.ai/getting-started/quickstart-textarea)並查看[演示影片](https://github.com/CopilotKit/CopilotKit?tab=readme-ov-file#demo)。 您可以輕鬆整合 Vercel AI SDK、OpenAI API、Langchain 和其他 LLM 供應商。您可以按照本[指南](https://docs.copilotkit.ai/getting-started/quickstart-chatbot)將聊天機器人整合到您的應用程式中。 基本概念是在幾分鐘內建立可用於基於 LLM 的應用程式的 AI 聊天機器人。 用例是巨大的,作為開發人員,我們絕對應該在下一個專案中嘗試使用 CopilotKit。 CopilotKit 在 GitHub 上擁有超過 4,200 個星星,發布了 200 多個版本,這意味著它們正在不斷改進。 {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} --- 13.[自動完成](https://github.com/withfig/autocomplete)- IDE 風格的自動完成功能適用於您現有的終端和 shell。 ---------------------------------------------------------------------------------- ![自動完成](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8i8vcidsa023jf8r9382.png) [Fig](https://fig.io/?ref=github_autocomplete)讓命令列對個人來說更容易,對團隊來說更具協作性。 他們最受歡迎的產品是自動完成。當您鍵入時,Fig 會在現有終端機中彈出子命令、選項和上下文相關的參數。 最好的部分是您也可以將 Fig 的自動完成功能用於您自己的工具。以下是建立私人完成的方法: ``` import { ai } from "@fig/autocomplete-generators" ... generators: [ ai({ // the prompt prompt: "Generate a git commit message", // Send any relevant local context. message: async ({ executeShellCommand }) => { return executeShellCommand("git diff") }, //Turn each newline into a suggestion (can specify instead a `postProcess1 function if more flexibility is required) splitOn: "\n", }) ] ``` 您可以閱讀[Fig.io/docs](https://fig.io/docs/getting-started)了解如何開始。 他們在 GitHub 上有 24k+ Stars,這對於經常使用 shell 或終端機的開發人員來說非常有用。 {% cta https://github.com/withfig/autocomplete %} 星狀自動完成 ⭐️ {% endcta %} --- 14. [Tooljet](https://github.com/ToolJet/ToolJet) - 用於建立業務應用程式的低程式碼平台。 ---------------------------------------------------------------------- ![工具噴射器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhipvjl2wnthjccgrpij.png) 我們都建立前端,但它通常非常複雜並且涉及很多因素。這樣可以省去很多麻煩。 ToolJet 是一個開源低程式碼框架,可以用最少的工程工作來建置和部署內部工具。 ToolJet 的拖放式前端建構器可讓您在幾分鐘內建立複雜的響應式前端。 您可以整合各種資料來源,包括PostgreSQL、MongoDB、Elasticsearch等資料庫;具有 OpenAPI 規範和 OAuth2 支援的 API 端點; SaaS 工具,例如 Stripe、Slack、Google Sheets、Airtable 和 Notion;以及 S3、GCS 和 Minio 等物件儲存服務來取得和寫入資料。一切 :) 這就是 Tooljet 的工作原理。 ![工具噴射器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6vv09z7ioma1ce2ttei.png) 您可以在 ToolJet 中開發多步驟工作流程以自動化業務流程。除了建置和自動化工作流程之外,ToolJet 還可以在您的應用程式中輕鬆整合這些工作流程。 ![工作流程](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eh2vk3kih9fhck6okf67.png) 您可以閱讀此[快速入門指南](https://docs.tooljet.com/docs/getting-started/quickstart-guide),該指南向您展示如何使用 ToolJet 在幾分鐘內建立員工目錄應用程式。該應用程式將讓您透過漂亮的用戶介面追蹤和更新員工資訊。 查看可用[功能列表](https://github.com/ToolJet/ToolJet?tab=readme-ov-file#all-features),包括 45 多個內建響應式元件、50 多個資料來源等等。 您可以閱讀[文件](https://docs.tooljet.com/docs/)並查看[操作指南](https://docs.tooljet.com/docs/how-to/use-url-params-on-load)。 它們在 GitHub 上有 26k+ Stars,並且基於 JavaScript 建置。他們也獲得了 GitHub 的資助,從而建立了巨大的信任。 {% cta https://github.com/ToolJet/ToolJet %} Star ToolJet ⭐️ {% endcta %} --- 15. [Apitable](https://github.com/apitable/apitable) - 用於建立協作應用程式的 API 導向的低程式碼平台。 --------------------------------------------------------------------------------- ![有能力的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58syhvpb2fn6hhlyrtst.png) APITable 是一個面向 API 的低程式碼平台,用於建立協作應用程式,並表示它比所有其他 Airtable 開源替代品都要好。 有很多很酷的功能,例如: - 即時協作。 ![即時協作](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58kpvpab2nj92421yvy3.gif) - 您可以產生自動表單。 ![形式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jo084gg0cd9xiud3nz3.gif) - 無限的跨錶連結。 ![交叉表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jnvb9sdp3uqrcn55hwug.gif) - API 第一個面板。 ![API第一個面板](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7u48ue4rl0q41rhh6bif.gif) - 強大的行/列功能。 ![行列](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/apxqwp84awdbj7cdw5yu.gif) 您可以閱讀完整的[功能清單](https://github.com/apitable/apitable?tab=readme-ov-file#-features)。 您可以嘗試[apitable](https://aitable.ai/)並在 apitable 的[live Gitpod demo](https://gitpod.io/#https://github.com/apitable/apitable)中查看該專案的演示。 您也可以閱讀[安裝指南](https://github.com/apitable/apitable?tab=readme-ov-file#installation),在本機或雲端運算環境中安裝 APITable。 {% cta https://github.com/apitable/apitable %} Star Apitable ⭐️ {% endcta %} --- 16. [n8n](https://github.com/n8n-io/n8n) - 工作流程自動化工具。 ----------------------------------------------------- ![n8n](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4pqsc84nhgj0b9dhfaxo.png) n8n 是一個可擴展的工作流程自動化工具。透過公平程式碼分發模型,n8n 將始終擁有可見的原始程式碼,可用於自託管,並允許您加入自訂函數、邏輯和應用程式。 每個開發人員都想使用的工具。自動化是生產力和簡單性的關鍵。 ![n8n](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxnp57kw5szbpj6mfs1p.png) n8n 基於節點的方法使其具有高度通用性,使您能夠將任何事物連接到任何事物。 有[400 多個集成選項](https://n8n.io/integrations),這幾乎是瘋狂的! 您可以看到所有[安裝](https://docs.n8n.io/choose-n8n/)選項,包括 Docker、npm 和自架。 開始使用以下命令。 ``` npx n8n ``` 此命令將下載啟動 n8n 所需的所有內容。然後,您可以透過開啟`http://localhost:5678`來存取 n8n 並開始建置工作流程。 在 YouTube 上觀看此[快速入門影片](https://www.youtube.com/watch?v=1MwSoB0gnM4)! {% 嵌入 https://www.youtube.com/watch?v=1MwSoB0gnM4 %} 您可以閱讀[文件](https://docs.n8n.io/)並閱讀本[指南](https://docs.n8n.io/try-it-out/),以便根據您的需求快速開始。 他們還提供初學者和中級[課程,](https://docs.n8n.io/courses/)以便輕鬆學習。 他們在 GitHub 上有 39k+ Stars,並提供兩個包供整體使用。 {% cta https://github.com/n8n-io/n8n %} 明星 n8n ⭐️ {% endcta %} --- 17. [DOMPurify](https://github.com/cure53/DOMPurify) - 一個僅限 DOM、超快、超級容忍 XSS 的 HTML 清理程式。 ---------------------------------------------------------------------------------------- ![DOM純化](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r846r2hmmw9d9wzvbocz.png) DOMPurify 是一款僅限 DOM、超快、超級容忍 XSS 的 HTML、MathML 和 SVG 清理工具。作為開發人員,我們的應用程式需要它來確保它們足夠安全。 DOMPurify 可以淨化 HTML 並防止 XSS 攻擊。 您可以向 DOMPurify 提供一個充滿髒 HTML 的字串,它將傳回一個包含乾淨 HTML 的字串(除非另有配置)。 DOMPurify 將刪除所有包含危險 HTML 的內容,從而防止 XSS 攻擊和其他惡意行為。這也太快了。 他們使用瀏覽器提供的技術並將其轉變為 XSS 過濾器。您的瀏覽器速度越快,DOMPurify 的速度就越快。 DOMPurify 使用 JavaScript 編寫,適用於所有現代瀏覽器(Safari (10+)、Opera (15+)、Edge、Firefox 和 Chrome - 以及幾乎所有使用 Blink、Gecko 或 WebKit 的其他瀏覽器)。它不會在 MSIE 或其他舊版瀏覽器上中斷。它根本什麼都不做。 開始使用以下 npm 指令。 ``` npm install dompurify npm install jsdom // or use the unminified development version <script type="text/javascript" src="src/purify.js"></script> ``` 您可以這樣使用它。 ``` const createDOMPurify = require('dompurify'); const { JSDOM } = require('jsdom'); const window = new JSDOM('').window; const DOMPurify = createDOMPurify(window); const clean = DOMPurify.sanitize('<b>hello there</b>'); ``` 如果您遇到問題,請參閱[文件](https://github.com/cure53/DOMPurify?tab=readme-ov-file#how-do-i-use-it)。他們已經記錄了使用腳本或在伺服器端執行它。 您可以看到一些 [純化樣品](https://github.com/cure53/DOMPurify?tab=readme-ov-file#some-purification-samples-please)並觀看[現場演示](https://cure53.de/purify)。 使用起來也非常簡單。 DOMPurify 於 2014 年 2 月啟動,同時版本已達 v3.1.0。 其中涉及到很多概念,我渴望探索它們。如果您有任何與此相關的令人興奮的事情,請告訴我。 我發現的另一個有用的替代方案是[validator.js](https://github.com/validatorjs/validator.js) 。 他們在 GitHub 上擁有超過 12,000 顆星,被超過 30 萬開發者使用,每週下載量超過 5,475,000 次,這使得他們非常可信。 {% cta https://github.com/cure53/DOMPurify %} 明星 DOMPurify ⭐️ {% endcta %} --- 18. [OpenDevin](https://github.com/OpenDevin/OpenDevin) - 更少的程式碼,更多的內容。 ----------------------------------------------------------------------- ![奧彭文](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4on63bb02g4x4ny8gtcn.png) ![奧彭文](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0yepod2rye2jk5r12dt.png) 這是一個開源專案,旨在複製 Devin,一名自主人工智慧軟體工程師,能夠執行複雜的工程任務並在軟體開發專案上與用戶積極協作。該計畫致力於透過開源社群的力量複製、增強和創新 Devin。 只是想讓你知道,這是在德文被介紹之前。 您可以閱讀帶有要求的[安裝說明](https://github.com/OpenDevin/OpenDevin?tab=readme-ov-file#installation)。 他們使用 LiteLLM,因此您可以使用任何基礎模型來執行 OpenDevin,包括 OpenAI、Claude 和 Gemini。 如果您想為 OpenDevin 做出貢獻,您可以查看 [演示](https://github.com/OpenDevin/OpenDevin/blob/main/README.md#opendevin-code-less-make-more)和[貢獻指南](https://github.com/OpenDevin/OpenDevin/blob/main/CONTRIBUTING.md)。 它在 GitHub 上擁有超過 10,700 個 Star,並且正在快速成長。 {% cta https://github.com/OpenDevin/OpenDevin %} 明星 OpenDevin ⭐️ {% endcta %} --- 19. [Amplification-](https://github.com/amplication/amplication)後端開發平台。 ----------------------------------------------------------------------- ![放大](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7yi3kvwrniredj4lp5r.png) 我想我們都同意,如果我們要達到標準,設定後端並從頭開始是很困難的。 我知道 Appwrite 和 Supabase 在功能方面要好得多,但每種情況都是獨特的,這可能會點擊而不是那些。 ![放大](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5wud5sef1lpwzi8zdq2.png) Amplication 旨在徹底改變可擴展且安全的 Node.js 應用程式的建立。 他們消除了重複的編碼任務,並提供可立即投入生產的基礎設施程式碼,這些程式碼根據您的規範精心定制,並遵循行業最佳實踐。 其用戶友好的介面促進了 API、資料模型、資料庫、身份驗證和授權的無縫整合。 Amplication 建立在靈活的、基於插件的架構之上,允許輕鬆定製程式碼並提供大量整合選項。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3lc27fgvk8yearir13z.png) ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zgix42tplg9hwko3a7u.png) 您可以閱讀[文件](https://docs.amplication.com/)並查看可用的[社群插件](https://docs.amplication.com/plugins-list/)清單。 他們還提供了[逐步教程](https://docs.amplication.com/tutorials/#step-by-step-tutorials),以幫助您使用 Angular 或 React 建立應用程式。 Amplification 在 GitHub 上擁有超過 13k 顆星,發布了 170 多個版本,因此它們不斷發展。 {% cta https://github.com/amplication/amplication %} 星狀放大 ⭐️ {% endcta %} --- 20. [Embla 旋轉木馬](https://github.com/davidjerleke/embla-carousel)-。 ------------------------------------------------------------------ ![Embla 旋轉木馬](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aj2expoo15t6xhgcm3hi.png) 我們都在應用程式中使用輪播,有時會切換到網格佈局,因為輪播並不總是好看,但這會改變您對輪播的看法。 我之所以了解 Embla Carousel,是因為 Shadcn/ui 在他們的 UI 系統中使用了它。 Embla Carousel 是一個簡單的輪播庫,具有出色的流暢運動和出色的滑動精度。它與庫無關、無依賴性且 100% 開源。 如果您不確定,我建議您查看[基本的實例](https://www.embla-carousel.com/examples/predefined/)。 ![例子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/paqu3ozlvhk5km5746pe.png) ![例子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qxfvmn83et836zon4ua.png) ![例子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abukp6j29gsaade7eci8.png) ![例子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/locv2kqksvpl0ha8a9te.png) 我最喜歡的是視差,它可以提供非常酷且平滑的過渡。 它們支援 CDN、react、Vue、Svelte 和 Solid。 開始使用以下 npm 指令 (react)。 ``` npm install embla-carousel-react --save ``` 您可以這樣使用它。 Embla Carousel 提供了方便的 useEmblaCarousel 鉤子,用於與 React 無縫整合。最小的設定需要一個溢出包裝器和一個滾動容器。 `useEmblaCarousel`掛鉤將 Embla Carousel 選項作為第一個參數。您還需要使用 useEffect 存取 API ``` import React, { useEffect } from 'react' import useEmblaCarousel from 'embla-carousel-react' export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false }) useEffect(() => { if (emblaApi) { console.log(emblaApi.slideNodes()) // Access API } }, [emblaApi]) return ( <div className="embla" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> ) } ``` 他們還提供了一組插件,您可以加入它們以實現自動播放等額外功能。 ``` npm install embla-carousel-autoplay --save ``` ``` import React, { useEffect } from 'react' import useEmblaCarousel from 'embla-carousel-react' import Autoplay from 'embla-carousel-autoplay' export function EmblaCarousel() { const [emblaRef] = useEmblaCarousel({ loop: false }, [Autoplay()]) return ( <div className="embla" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> ) } ``` 尋找[插件的完整列表](https://www.embla-carousel.com/plugins/),包括自動滾動和滾輪手勢。 您可以閱讀有關如何實現不同部分(例如斷點或上一個/下一個按鈕)的[文件](https://www.embla-carousel.com/get-started/)和[指南](https://www.embla-carousel.com/guides/)。 最讓我驚訝的部分是,您可以使用他們的[生成器](https://www.embla-carousel.com/examples/generator/)使用您自己的一組選項來產生自訂輪播。 ![發電機](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wlq7l44bwl681644xf3.png) ![發電機](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2r1y3kr926h87clbqosw.png) 它們在 GitHub 上擁有 4.9K 顆星,並被超過 26000 名開發人員使用。如果我必須使用一個,我肯定會使用這個。 {% cta repo %} 明星名稱 ⭐️ {% endcta %} --- [21.Documenso](https://github.com/documenso/documenso) - 開源 DocuSign 替代方案。 -------------------------------------------------------------------------- ![文獻](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cttvudzx02wqsu04qt8v.gif) 如果您從事自由職業並需要簽署協議,這是最佳選擇。我們不應該浪費時間,而應該專注於重要的事情。 以數位方式簽署文件應該既快速又簡單,並且應該成為全球簽署的每個文件的最佳實踐。 如今,這在技術上相當簡單,但它也為每個簽名引入了一個新方:簽名工具提供者。 此專案的技術堆疊包括 TypeScript、Next.js、Prisma、Tailwind CSS、shadcn/ui、NextAuth.js、react-email、tRPC、@documenso/pdf-sign、React-PDF、PDF-Lib、Stripe 和韋爾塞爾。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ziz58jqi2qtl6p6sx62w.png) ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8zrln5zlywkb6k10n09.png) 免費套餐可讓您每月簽署 10 份文件,這已經足夠了。 您可以閱讀本文以了解如何[設定專案](https://github.com/documenso/documenso?tab=readme-ov-file#developer-setup)。 您可以閱讀[文件](https://github.com/documenso/documenso?tab=readme-ov-file#developer-quickstart)。 我知道這不是一個非常廣泛的用例,但您仍然可以從程式碼中學習,因此這始終是一個優點。 他們在 GitHub 上擁有超過 5800 顆星,並且發布了`v1.5`版本。 不是很流行但非常有用。 {% cta https://github.com/documenso/documenso %} 明星 documenso ⭐️ {% endcta %} --- 哇! 這花了我很長很長的時間來寫。我希望你喜歡它。 我知道人工智慧工具有時太多了,但我們應該使用它們來讓我們的工作更輕鬆。我的意思是,這就是我們所做的正確的事情,讓生活變得更輕鬆。 我嘗試涵蓋廣泛的工具。 不管怎樣,請讓我們知道您的想法以及您計劃在您的工作流程中使用這些工具嗎? 祝你有美好的一天!直到下一次。 我建立了很多技術內容,因此如果您能在 Twitter 上關注我來支持我,我將不勝感激。 |如果你喜歡這類東西, 請關注我以了解更多:) | [![用戶名 Anmol_Codes 的 Twitter 個人資料](https://img.shields.io/badge/Twitter-d5d5d5?style=for-the-badge&logo=x&logoColor=0A0209)](https://twitter.com/Anmol_Codes) [![用戶名 Anmol-Baranwal 的 GitHub 個人資料](https://img.shields.io/badge/github-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Anmol-Baranwal) [![用戶名 Anmol-Baranwal 的 LinkedIn 個人資料](https://img.shields.io/badge/LinkedIn-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/Anmol-Baranwal/) | |------------|----------| 關注 Taipy 以了解更多此類內容。 {% 嵌入 https://dev.to/taipy %} --- 原文出處:https://dev.to/taipy/21-tools-to-take-your-dev-skills-to-the-moon-53mf

Supabase Auth 現在支援匿名登入

Supabase Auth 現在支援[匿名登錄](https://supabase.com/docs/guides/auth/auth-anonymous),這是社群[最需要的功能](https://github.com/supabase/auth/issues/68)之一。 {% cta https://supabase.com/ga-week %} ⚡️ 了解有關 GA 週的更多資訊 {% endcta %} 匿名登入可用於建立尚未註冊您的應用程式的**臨時使用者**。這降低了新用戶試用您的產品的阻力,因為他們不必提供任何註冊憑證。 {% 嵌入 https://youtu.be/WNN7Pp5Ftk4 %} 啟用匿名登入 ------ 您今天可以從儀表板為您的專案[啟用匿名登入](https://supabase.com/dashboard/project/_/settings/auth): ![啟用功能截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24n0kagpgagq3h2bw145.png) 對於本機開發,請升級 Supabase CLI 並將設定新增至`config.toml`檔案: ``` [auth] enable_anonymous_sign_ins = true ``` 現在您可以透過[Javascript](https://supabase.com/docs/reference/javascript/auth-signinanonymously) 、 [Flutter](https://supabase.com/docs/reference/dart/auth-signinanonymously)或[Swift](https://supabase.com/docs/reference/swift/auth-signinanonymously) SDK 建立匿名使用者。以下是如何使用`supabase-js`建立匿名用戶。 ``` const { data, error } = await supabase .auth .signInAnonymously() ``` 術語 -- 使用匿名登入建立的個人資料也會經過`authenticated` ! 呼叫`.signInAnonymously()`後,您已將使用者移至驗證流程,我們將他們視為登入使用者: ![範例圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjr5r7vj7pu4a8epqjol.png) 限制匿名用戶的存取 --------- 與永久使用者一樣,匿名使用者也保留在`auth.users`表中: |編號 |角色 |電子郵件 |是\_匿名 | | ------------------------------------------------ | ------------- | ----------------- | ------------ | | e053e470-afa1-4625-8963-37adb862fd11 |已驗證 |空|真實 | | 5563108e-ac81-4063-9288-4f3db068efa1 |已驗證 | [email protected] |假 | 匿名用戶可以透過用戶 JWT 中傳回的`is_anonymous`聲明來辨識,該聲明可從行級安全策略 (RLS) 存取。如果您想限制對應用程式中某些功能的存取,這會很有幫助。 例如,假設我們有一個線上論壇,用戶可以在其中建立和閱讀貼文。 給定這個表來儲存帖子: ``` create table public.posts ( id serial primary key, name text not null, description text ); ``` 如果我們只想允許永久用戶建立帖子,我們可以透過檢查 JWT `select auth.jwt() ->> 'is_anonymous'`來檢查使用者是否是匿名的。 在 RLS 策略中使用此函數: ``` create policy "Only permanent users can create posts" on public.posts for insert to authenticated -- Note: user is still authenticated with check ( (select auth.jwt() ->> 'is_anonymous')::boolean is false ); ``` RLS 為我們提供了建立各種規則的充分靈活性。 例如,允許永久用戶對所有帖子進行讀取存取,並限制匿名用戶只能存取今天建立的帖子: ``` create policy "Limit access to anonymous users" on public.posts for select to authenticated -- Note: user is still authenticated using ( case when (select (auth.jwt() ->> 'is_anonymous'))::boolean is true then (created_at >= current_date) else true end ); ``` 將匿名用戶轉換為永久用戶 ------------ 在某些時候,匿名用戶可能決定他們想要建立一個貼文。我們在這裡提示他們註冊一個帳戶,將他們轉換為永久用戶。 > 當匿名使用者俱有與其關聯的身份時,他們被視為永久使用者。 轉換後,使用者 ID 保持不變,這表示與使用者 ID 關聯的任何資料都將被保留。 Supabase Auth 提供了 2 種方法來實現此目的: 1-連結電子郵件或電話身份 2-連結 OAuth 身份 連結電子郵件或電話身份 ----------- 若要連結電子郵件或電話身分: ``` const { data, error } = await supabase .auth .updateUser({ email }) ``` 連結 OAuth 身份 ----------- 要將 OAuth 身分連結到匿名用戶,您需要為專案[啟用手動連結](https://supabase.com/dashboard/project/_/settings/auth)。了解[身分連結](https://supabase.com/docs/guides/auth/auth-identity-linking)如何與 Supabase Auth 配合使用。 ![打開](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmyynoe9lqgn75owkb3f.png) 啟用後,您可以呼叫`linkIdentity()`方法: ``` const { data, error } = await supabase .auth .linkIdentity({ provider: 'google' }) ``` 冒充匿名用戶 ------ 在建立 RLS 策略來區分匿名使用者的存取權時,您可以利用 SQL 編輯器中的[使用者模擬功能](https://supabase.com/blog/studio-introducing-assistant)來測試您的策略: ![助理截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jlsj0419csvjtmrzg77.png) *SQL 編輯器中的資料庫角色設定。您可以從下拉清單中選擇使用者來模擬匿名使用者。* [使用者管理畫面](https://supabase.com/dashboard/project/_/auth/users)提供了匿名使用者過濾的選項,這可以幫助了解已建立了多少匿名使用者。 ![工具截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmx21h9idryi9yl4zi0s.png) 下一步是什麼 ------ 管理匿名用戶可能很棘手,尤其是當您的網站有大量訪客時。我們正在開發「自動清理」選項,以刪除超過 30 天不活動的匿名用戶。同時,由於匿名使用者儲存在資料庫的 auth 模式中,因此您可以透過執行下列查詢來清理孤立的匿名使用者: ``` -- deletes anonymous users created more than 30 days ago delete from auth.users where is_anonymous is true and created_at < now() - interval '30 days'; ``` 我們也正在開發[linter,](https://github.com/supabase/splinter/pull/28)以檢查您的 RLS 策略並突出顯示那些允許匿名用戶存取的策略 - 請繼續關注本月稍後的更新! 入門 -- - 文件:[匿名登入](https://supabase.com/docs/guides/auth/auth-anonymous) - API方法參考: [Javascript](https://supabase.com/docs/reference/javascript/auth-signinanonymously) 、 [Flutter](https://supabase.com/docs/reference/dart/auth-signinanonymously) 、 [Swift](https://supabase.com/docs/reference/swift/auth-signinanonymously) **更多關於 GA 週的訊息** - [斯帕巴斯威夫特](https://supabase.com/blog/supabase-swift) - [AWS Marketplace 上的 Supabase](https://supabase.com/blog/supabase-aws-marketplace) - [Supabase 開源黑客馬拉松 2024](https://supabase.com/blog/supabase-oss-hackathon) - [Supabase引導程式](https://supabase.com/blog/supabase-bootstrap) - \[分支現已公開 \](https://supabase.com/blog/branching-publicly-available) --- 原文出處:https://dev.to/supabase/supabase-auth-now-supports-anonymous-sign-ins-1j00

使用 AI-copilot(Next.js、gpt4、LangChain 和 CopilotKit)建立電子表格應用程式

**長話短說** -------- 在本文中,您將學習如何建立人工智慧驅動的電子表格應用程式,該應用程式允許您使用簡單的英語命令執行各種會計功能並輕鬆與資料互動。 我們將介紹如何: - 使用 Next.js 建立 Web 應用程式, - 使用 React Spreadsheet 建立電子表格應用程式,以及 - 使用 CopilotKit 將 AI 整合到軟體應用程式中。 - 讓電子表格更容易使用、更有趣 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ruxylrd07dga5ngw98np.gif) --- CopilotKit:建構應用內人工智慧副駕駛的框架 ========================== CopilotKit是一個[開源的AI副駕駛平台](https://github.com/CopilotKit/CopilotKit)。我們可以輕鬆地將強大的人工智慧整合到您的 React 應用程式中。 建造: - ChatBot:上下文感知的應用內聊天機器人,可以在應用程式內執行操作 💬 - CopilotTextArea:人工智慧驅動的文字字段,具有上下文感知自動完成和插入功能📝 - 聯合代理:應用程式內人工智慧代理,可以與您的應用程式和使用者互動🤖 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3us3vc140aun0dvrdof.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} (請原諒 AI 的拼字錯誤並給 CopilotKit 加上星號:) 現在回到文章! --- 先決條件 ---- 要完全理解本教程,您需要對 React 或 Next.js 有基本的了解。 以下是建立人工智慧驅動的電子表格應用程式所需的工具: - [React Spreadsheet](https://github.com/iddan/react-spreadsheet) - 一個簡單的包,使我們能夠在 React 應用程式中加入電子表格。 - [OpenAI API](https://platform.openai.com/api-keys) - 提供 API 金鑰,使我們能夠使用 ChatGPT 模型執行各種任務。 - [Tavily AI](https://tavily.com/) - 一個搜尋引擎,使人工智慧代理能夠在應用程式中進行研究並存取即時知識。 - [CopilotKit](https://github.com/CopilotKit) - 一個開源副駕駛框架,用於建立自訂 AI 聊天機器人、應用程式內 AI 代理程式和文字區域。 專案設定和套件安裝 --------- 首先,透過在終端機中執行以下程式碼片段來建立 Next.js 應用程式: ``` npx create-next-app spreadsheet-app ``` 選擇您首選的配置設定。在本教學中,我們將使用 TypeScript 和 Next.js App Router。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2zg8z22tdgmlv4wmfil.png) 接下來,安裝[OpenAI 函式庫](https://platform.openai.com/docs/introduction)、 [Heroicons](https://www.npmjs.com/package/@heroicons/react)和[React Spreadsheet](https://github.com/iddan/react-spreadsheet)套件及其相依性: ``` npm install openai react-spreadsheet scheduler @heroicons/react ``` 最後,安裝 CopilotKit 軟體套件。這些套件使我們能夠從 React 狀態檢索資料並將 AI copilot 新增至應用程式。 ``` npm install @copilotkit/react-ui @copilotkit/react-textarea @copilotkit/react-core @copilotkit/backend ``` 恭喜!您現在已準備好建立應用程式。 --- 建立電子表格應用程式 ---------- 在本節中,我將引導您使用 React Spreadsheet 建立電子表格應用程式。 該應用程式分為兩個元件: `Sidebar`和`SingleSpreadsheet` 。 要設定這些元件,請導航至 Next.js 應用程式資料夾並建立一個包含以下檔案的`components`資料夾: ``` cd app mkdir components && cd components touch Sidebar.tsx SingleSpreadsheet.tsx ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd9crph3qdenb2eikfoh.png) 將新建立的元件匯入到**`app/page.tsx`**檔案中。 ``` "use client"; import React, { useState } from "react"; //👇🏻 import the components import { SpreadsheetData } from "./types"; import Sidebar from "./components/Sidebar"; import SingleSpreadsheet from "./components/SingleSpreadsheet"; const Main = () => { return ( <div className='flex'> <p>Hello world</p> </div> ); }; export default Main; ``` 接下來,建立將包含電子表格資料的 React 狀態,並將它們作為 props 傳遞到元件中。 ``` const Main = () => { //👇🏻 holds the title and data within a spreadsheet const [spreadsheets, setSpreadsheets] = React.useState<SpreadsheetData[]>([ { title: "Spreadsheet 1", data: [ [{ value: "" }, { value: "" }, { value: "" }], [{ value: "" }, { value: "" }, { value: "" }], [{ value: "" }, { value: "" }, { value: "" }], ], }, ]); //👇🏻 represents the index of a spreadsheet const [selectedSpreadsheetIndex, setSelectedSpreadsheetIndex] = useState(0); return ( <div className='flex'> <Sidebar spreadsheets={spreadsheets} selectedSpreadsheetIndex={selectedSpreadsheetIndex} setSelectedSpreadsheetIndex={setSelectedSpreadsheetIndex} /> <SingleSpreadsheet spreadsheet={spreadsheets[selectedSpreadsheetIndex]} setSpreadsheet={(spreadsheet) => { setSpreadsheets((prev) => { console.log("setSpreadsheet", spreadsheet); const newSpreadsheets = [...prev]; newSpreadsheets[selectedSpreadsheetIndex] = spreadsheet; return newSpreadsheets; }); }} /> </div> ); }; ``` 此程式碼片段建立了 React 狀態,用於保存電子表格資料及其索引,並將它們作為 props 傳遞到元件中。 `Sidebar`元件接受所有可用的電子表格, `SingleSpreadsheet`元件接收所有電子表格,包括更新電子表格資料的`setSpreadsheet`函數。 將下面的程式碼片段複製到`Sidebar.tsx`檔案中。它顯示應用程式中的所有電子表格,並允許使用者在它們之間進行切換。 ``` import React from "react"; import { SpreadsheetData } from "../types"; interface SidebarProps { spreadsheets: SpreadsheetData[]; selectedSpreadsheetIndex: number; setSelectedSpreadsheetIndex: (index: number) => void; } const Sidebar = ({ spreadsheets, selectedSpreadsheetIndex, setSelectedSpreadsheetIndex, }: SidebarProps) => { return ( <div className='w-64 h-screen bg-gray-800 text-white overflow-auto p-5'> <ul> {spreadsheets.map((spreadsheet, index) => ( <li key={index} className={`mb-4 cursor-pointer ${ index === selectedSpreadsheetIndex ? "ring-2 ring-blue-500 ring-inset p-3 rounded-lg" : "p-3" }`} onClick={() => setSelectedSpreadsheetIndex(index)} > {spreadsheet.title} </li> ))} </ul> </div> ); }; export default Sidebar; ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c36qccuwa0knqokag5mk.gif) 更新`SingleSpreadsheet.tsx`文件,如下所示: ``` import React from "react"; import Spreadsheet from "react-spreadsheet"; import { SpreadsheetData, SpreadsheetRow } from "../types"; interface MainAreaProps { spreadsheet: SpreadsheetData; setSpreadsheet: (spreadsheet: SpreadsheetData) => void; } //👇🏻 adds a new row to the spreadsheet const addRow = () => { const numberOfColumns = spreadsheet.rows[0].length; const newRow: SpreadsheetRow = []; for (let i = 0; i < numberOfColumns; i++) { newRow.push({ value: "" }); } setSpreadsheet({ ...spreadsheet, rows: [...spreadsheet.rows, newRow], }); }; //👇🏻 adds a new column to the spreadsheet const addColumn = () => { const spreadsheetData = [...spreadsheet.data]; for (let i = 0; i < spreadsheet.data.length; i++) { spreadsheet.data[i].push({ value: "" }); } setSpreadsheet({ ...spreadsheet, data: spreadsheetData, }); }; const SingleSpreadsheet = ({ spreadsheet, setSpreadsheet }: MainAreaProps) => { return ( <div className='flex-1 overflow-auto p-5'> {/** -- Spreadsheet title ---*/} <div className='flex items-start'> {/** -- Spreadsheet rows and columns---*/} {/** -- Add column button ---*/} </div> {/** -- Add row button ---*/} </div> ); }; export default SingleSpreadsheet; ``` - 從上面的程式碼片段來看, ``` - The `SingleSpreadsheet.tsx` file includes the addRow and addColumn functions. ``` ``` - The `addRow` function calculates the current number of rows, adds a new row, and updates the spreadsheet accordingly. ``` ``` - Similarly, the `addColumn` function adds a new column to the spreadsheet. ``` ``` - The `SingleSpreadsheet` component renders placeholders for the user interface elements. ``` 更新`SingleSpreadsheet`元件以呈現電子表格標題、其資料以及新增行和列按鈕。 ``` return ( <div className='flex-1 overflow-auto p-5'> {/** -- Spreadsheet title ---*/} <input type='text' value={spreadsheet.title} className='w-full p-2 mb-5 text-center text-2xl font-bold outline-none bg-transparent' onChange={(e) => setSpreadsheet({ ...spreadsheet, title: e.target.value }) } /> {/** -- Spreadsheet rows and columns---*/} <div className='flex items-start'> <Spreadsheet data={spreadsheet.data} onChange={(data) => { console.log("data", data); setSpreadsheet({ ...spreadsheet, data: data as any }); }} /> {/** -- Add column button ---*/} <button className='bg-blue-500 text-white rounded-lg ml-6 w-8 h-8 mt-0.5' onClick={addColumn} > + </button> </div> {/** -- Add row button ---*/} <button className='bg-blue-500 text-white rounded-lg w-8 h-8 mt-5 ' onClick={addRow} > + </button> </div> ); ``` 為了確保一切按預期工作,請在`app`資料夾中建立一個`types.ts`文件,其中包含應用程式中聲明的所有靜態類型。 ``` export interface Cell { value: string; } export type SpreadsheetRow = Cell[]; export interface SpreadsheetData { title: string; rows: SpreadsheetRow[]; } ``` 恭喜! 🎉 您的電子表格應用程式應該可以完美執行。在接下來的部分中,您將了解如何新增 AI 副駕駛,以使用 CopilotKit 自動執行各種任務。 --- 使用 CopilotKit 改進應用程式功能 ---------------------- 在這裡,您將學習如何將 AI 副駕駛加入到電子表格應用程式,以使用 CopilotKit 自動執行複雜的操作。 CopilotKit 提供前端和[後端](https://docs.copilotkit.ai/getting-started/quickstart-backend)套件。它們使您能夠插入 React 狀態並使用 AI 代理在後端處理應用程式資料。 首先,我們將 CopilotKit React 元件新增到應用程式前端。 ### 將 CopilotKit 加入前端 在`app/page.tsx`中,將以下程式碼片段加入`Main`元件的頂部。 ``` import "@copilotkit/react-ui/styles.css"; import { CopilotKit } from "@copilotkit/react-core"; import { CopilotSidebar } from "@copilotkit/react-ui"; import { INSTRUCTIONS } from "./instructions"; const HomePage = () => { return ( <CopilotKit url='/api/copilotkit'> <CopilotSidebar instructions={INSTRUCTIONS} labels={{ initial: "Welcome to the spreadsheet app! How can I help you?", }} defaultOpen={true} clickOutsideToClose={false} > <Main /> </CopilotSidebar> </CopilotKit> ); }; const Main = () => { //--- Main component // }; export default HomePage; ``` - 從上面的程式碼片段來看, ``` - I imported the CopilotKit, its sidebar component, and CSS file to use its frontend components within the application. ``` ``` - The [CopilotKit component](https://docs.copilotkit.ai/reference/CopilotKit) accepts a `url` prop that represents the API server route where CopilotKit will be configured. ``` ``` - The Copilot component also renders the [CopilotSidebar component](https://docs.copilotkit.ai/reference/CopilotSidebar) , allowing users to provide custom instructions to the AI copilot within the application. ``` ``` - Lastly, you can export the `HomePage` component containing the `CopilotSidebar` and the `Main` components. ``` 從上面的程式碼片段中,您會注意到`CopilotSidebar`元件有一個`instructions`屬性。此屬性使您能夠為 CopilotKit 提供額外的上下文或指導。 因此,在`app`資料夾中建立`instructions.ts`檔案並將這些[命令](https://github.com/CopilotKit/spreadsheet-demo/blob/main/src/app/instructions.ts)複製到該檔案中。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whs8k2ly9as7j4wn6h5o.png) 接下來,您需要將 CopilotKit 插入應用程式的狀態以存取應用程式的資料。為了實現這一點,CopilotKit 提供了兩個鉤子: [useCopilotAction](https://docs.copilotkit.ai/reference/useCopilotAction)和[useMakeCopilotReadable](https://docs.copilotkit.ai/reference/useMakeCopilotReadable) 。 [useCopilotAction](https://docs.copilotkit.ai/reference/useCopilotAction)掛鉤可讓您定義 CopilotKit 執行的動作。它接受包含以下參數的物件: - `name` - 操作的名稱。 - `description` - 操作的描述。 - `parameters` - 包含所需參數清單的陣列。 - `render` - 預設的自訂函數或字串。 - `handler` - 由操作觸發的可執行函數。 ``` useCopilotAction({ name: "sayHello", description: "Say hello to someone.", parameters: [ { name: "name", type: "string", description: "name of the person to say greet", }, ], render: "Process greeting message...", handler: async ({ name }) => { alert(`Hello, ${name}!`); }, }); ``` [useMakeCopilotReadable](https://docs.copilotkit.ai/reference/useMakeCopilotReadable)掛鉤向 CopilotKit 提供應用程式狀態。 ``` import { useMakeCopilotReadable } from "@copilotkit/react-core"; const appState = ...; useMakeCopilotReadable(JSON.stringify(appState)); ``` 現在,讓我們回到電子表格應用程式。在`SingleSpreadsheet`元件中,將應用程式狀態傳遞到 CopilotKit 中,如下所示。 ``` import { useCopilotAction, useMakeCopilotReadable, } from "@copilotkit/react-core"; const SingleSpreadsheet = ({ spreadsheet, setSpreadsheet }: MainAreaProps) => { //👇🏻 hook for providing the application state useMakeCopilotReadable( "This is the current spreadsheet: " + JSON.stringify(spreadsheet) ); // --- other lines of code }; ``` 接下來,您需要在`SingleSpreadsheet`元件中新增兩個操作,該元件在使用者更新電子表格資料並使用 CopilotKit 新增資料行時執行。 在繼續之前,請在`app`資料夾中建立一個包含`canonicalSpreadsheetData.ts`檔案的`utils`資料夾。 ``` cd app mkdir utils && cd utils touch canonicalSpreadsheetData.ts ``` 將下面的程式碼片段複製到檔案中。它接受對電子表格所做的更新,並將其轉換為電子表格中資料行所需的格式。 ``` import { SpreadsheetRow } from "../types" export interface RowLike { cells: CellLike[] | undefined; } export interface CellLike { value: string; } export function canonicalSpreadsheetData( rows: RowLike[] | undefined ): SpreadsheetRow[] { const canonicalRows: SpreadsheetRow[] = []; for (const row of rows || []) { const canonicalRow: SpreadsheetRow = []; for (const cell of row.cells || []) { canonicalRow.push({value: cell.value}); } canonicalRows.push(canonicalRow); } return canonicalRows; } ``` 現在,讓我們使用`SingleSpreadsheet`元件中的`useCopilotAction`掛鉤建立操作。複製下面的第一個操作: ``` import { canonicalSpreadsheetData } from "../utils/canonicalSpreadsheetData"; import { PreviewSpreadsheetChanges } from "./PreviewSpreadsheetChanges"; import { SpreadsheetData, SpreadsheetRow } from "../types"; import { useCopilotAction } from "@copilotkit/react-core"; useCopilotAction({ name: "suggestSpreadsheetOverride", description: "Suggest an override of the current spreadsheet", parameters: [ { name: "rows", type: "object[]", description: "The rows of the spreadsheet", attributes: [ { name: "cells", type: "object[]", description: "The cells of the row", attributes: [ { name: "value", type: "string", description: "The value of the cell", }, ], }, ], }, { name: "title", type: "string", description: "The title of the spreadsheet", required: false, }, ], render: (props) => { const { rows } = props.args const newRows = canonicalSpreadsheetData(rows); return ( <PreviewSpreadsheetChanges preCommitTitle="Replace contents" postCommitTitle="Changes committed" newRows={newRows} commit={(rows) => { const updatedSpreadsheet: SpreadsheetData = { title: spreadsheet.title, rows: rows, }; setSpreadsheet(updatedSpreadsheet); }} /> ) }, handler: ({ rows, title }) => { // Do nothing. // The preview component will optionally handle committing the changes. }, }); ``` 上面的程式碼片段執行使用者的任務並使用 CopilotKit 產生 UI 功能顯示結果預覽。 `suggestSpreadsheetOverride`操作傳回一個自訂元件 ( `PreviewSpreadsheetChanges` ),該元件接受以下內容為 props: - 要新增到電子表格的新資料行, - 一些文字 - `preCommitTitle`和`postCommitTitle` ,以及 - 更新電子表格的`commit`函數。 您很快就會學會如何使用它們。 在元件資料夾中建立`PreviewSpreadsheetChanges`元件,並將下列程式碼片段複製到檔案中: ``` import { CheckCircleIcon } from '@heroicons/react/20/solid' import { SpreadsheetRow } from '../types'; import { useState } from 'react'; import Spreadsheet from 'react-spreadsheet'; export interface PreviewSpreadsheetChanges { preCommitTitle: string; postCommitTitle: string; newRows: SpreadsheetRow[]; commit: (rows: SpreadsheetRow[]) => void; } export function PreviewSpreadsheetChanges(props: PreviewSpreadsheetChanges) { const [changesCommitted, setChangesCommitted] = useState(false); const commitChangesButton = () => { return ( <button className="inline-flex items-center gap-x-2 rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" onClick={() => { props.commit(props.newRows); setChangesCommitted(true); }} > {props.preCommitTitle} </button> ); } const changesCommittedButtonPlaceholder = () => { return ( <button className=" inline-flex items-center gap-x-2 rounded-md bg-gray-100 px-3.5 py-2.5 text-sm font-semibold text-green-600 shadow-sm cursor-not-allowed" disabled > {props.postCommitTitle} <CheckCircleIcon className="-mr-0.5 h-5 w-5" aria-hidden="true" /> </button> ); } return ( <div className="flex flex-col"> <Spreadsheet data={props.newRows} /> <div className="mt-5"> {changesCommitted ? changesCommittedButtonPlaceholder() : commitChangesButton() } </div> </div> ); } ``` `PreviewSpreadsheetChanges`元件傳回一個電子表格,其中包含從請求產生的資料和一個按鈕(帶有`preCommitTitle`文字),該按鈕允許您將這些變更提交到主電子表格表(透過觸發`commit`函數)。這可確保您在將結果新增至電子表格之前對結果感到滿意。 將下面的第二個操作加入到`SingleSpreadsheet`元件。 ``` useCopilotAction({ name: "appendToSpreadsheet", description: "Append rows to the current spreadsheet", parameters: [ { name: "rows", type: "object[]", description: "The new rows of the spreadsheet", attributes: [ { name: "cells", type: "object[]", description: "The cells of the row", attributes: [ { name: "value", type: "string", description: "The value of the cell", }, ], }, ], }, ], render: (props) => { const status = props.status; const { rows } = props.args const newRows = canonicalSpreadsheetData(rows); return ( <div> <p>Status: {status}</p> <Spreadsheet data={newRows} /> </div> ) }, handler: ({ rows }) => { const canonicalRows = canonicalSpreadsheetData(rows); const updatedSpreadsheet: SpreadsheetData = { title: spreadsheet.title, rows: [...spreadsheet.rows, ...canonicalRows], }; setSpreadsheet(updatedSpreadsheet); }, }); ``` `appendToSpreadsheet`操作透過在電子表格中新增資料行來更新電子表格。 以下是操作的簡短示範: \[https://www.youtube.com/watch?v=kGQ9xl5mSoQ\] 最後,在`Main`元件中新增一個操作,以便在使用者提供指令時建立一個新的電子表格。 ``` useCopilotAction({ name: "createSpreadsheet", description: "Create a new spreadsheet", parameters: [ { name: "rows", type: "object[]", description: "The rows of the spreadsheet", attributes: [ { name: "cells", type: "object[]", description: "The cells of the row", attributes: [ { name: "value", type: "string", description: "The value of the cell", }, ], }, ], }, { name: "title", type: "string", description: "The title of the spreadsheet", }, ], render: (props) => { const { rows, title } = props.args; const newRows = canonicalSpreadsheetData(rows); return ( <PreviewSpreadsheetChanges preCommitTitle="Create spreadsheet" postCommitTitle="Spreadsheet created" newRows={newRows} commit={ (rows) => { const newSpreadsheet: SpreadsheetData = { title: title || "Untitled Spreadsheet", rows: rows, }; setSpreadsheets((prev) => [...prev, newSpreadsheet]); setSelectedSpreadsheetIndex(spreadsheets.length); }} /> ); }, handler: ({ rows, title }) => { // Do nothing. // The preview component will optionally handle committing the changes. }, }); ``` 恭喜!您已成功為此應用程式建立所需的操作。現在,讓我們將應用程式連接到 Copilotkit 後端。 ### 將 Tavily AI 和 OpenAI 加入到 CopilotKit 在本教程的開頭,我向您介紹了[Tavily AI](https://tavily.com/) (一個為 AI 代理提供知識的搜尋引擎)和 OpenAI(一個使我們能夠存取[GPT-4 AI 模型的](https://openai.com/gpt-4)庫)。 在本部分中,您將了解如何取得 Tavily 和 OpenAI API 金鑰並將它們整合到 CopilotKit 中以建立高級智慧應用程式。 造訪[Tavily AI 網站](https://app.tavily.com/sign-in),建立一個帳戶,然後將您的 API 金鑰複製到您專案的`.env.local`檔案中。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8shpxr5hh9r9kggk1jv.png) 接下來,導覽至[OpenAI 開發者平台](https://platform.openai.com/api-keys),建立 API 金鑰,並將其複製到`.env.local`檔案中。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4ugtobr70wg6z6ru3cj.png) 以下是`.env.local`檔案的預覽,其中包括 API 金鑰並指定要使用的 OpenAI 模型。請注意,存取 GPT-4 模型需要[訂閱 ChatGPT Plus](https://openai.com/chatgpt/pricing) 。 ``` TAVILY_API_KEY=<your_API_key> OPENAI_MODEL=gpt-4-1106-preview OPENAI_API_KEY=<your_API_key> ``` 回到我們的應用程式,您需要為 Copilot 建立 API 路由。因此,建立一個包含`route.ts`的`api/copilotkit`資料夾並新增一個`tavily.ts`檔案。 ``` cd app mkdir api && cd api mkdir copilotkit && cd copilotkit touch route.ts tavily.ts ``` 在`tavily.ts`檔案中建立一個函數,該函數接受使用者的查詢,使用 Tavily Search API 對查詢進行研究,並使用[OpenAI GPT-4 模型](https://openai.com/gpt-4)總結結果。 ``` import OpenAI from "openai"; export async function research(query: string) { //👇🏻 sends the request to the Tavily Search API const response = await fetch("https://api.tavily.com/search", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ api_key: process.env.TAVILY_API_KEY, query, search_depth: "basic", include_answer: true, include_images: false, include_raw_content: false, max_results: 20, }), }); //👇🏻 the response const responseJson = await response.json(); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! }); //👇🏻 passes the response into the OpenAI GPT-4 model const completion = await openai.chat.completions.create({ messages: [ { role: "system", content: `Summarize the following JSON to answer the research query \`"${query}"\`: ${JSON.stringify( responseJson )} in plain English.`, }, ], model: process.env.OPENAI_MODEL, }); //👇🏻 returns the result return completion.choices[0].message.content; } ``` 最後,您可以透過將使用者的查詢傳遞到函數中並向 CopilotKit 提供其回應來執行`route.ts`檔案中的`research`函數。 ``` import { CopilotBackend, OpenAIAdapter } from "@copilotkit/backend"; import { Action } from "@copilotkit/shared"; import { research } from "./tavily"; //👇🏻 carries out a research on the user's query const researchAction: Action<any> = { name: "research", description: "Call this function to conduct research on a certain query.", parameters: [ { name: "query", type: "string", description: "The query for doing research. 5 characters or longer. Might be multiple words", }, ], handler: async ({ query }) => { console.log("Research query: ", query); const result = await research(query); console.log("Research result: ", result); return result; }, }; export async function POST(req: Request): Promise<Response> { const actions: Action<any>[] = []; if (process.env.TAVILY_API_KEY!) { actions.push(researchAction); } const copilotKit = new CopilotBackend({ actions: actions, }); const openaiModel = process.env.OPENAI_MODEL; return copilotKit.response(req, new OpenAIAdapter({ model: openaiModel })); } ``` 恭喜!您已完成本教學的專案。 結論 -- [CopilotKit](https://copilotkit.ai/)是一款令人難以置信的工具,可讓您在幾分鐘內將 AI Copilot 加入到您的產品中。無論您是對人工智慧聊天機器人和助理感興趣,還是對複雜任務的自動化感興趣,CopilotKit 都能讓您輕鬆實現。 如果您需要建立 AI 產品或將 AI 工具整合到您的軟體應用程式中,您應該考慮 CopilotKit。 您可以在 GitHub 上找到本教學的源程式碼: https://github.com/CopilotKit/spreadsheet-demo 感謝您的閱讀! --- 原文出處:https://dev.to/copilotkit/build-an-ai-powered-spreadsheet-app-nextjs-langchain-copilotkit-109d

加入我們參加下一個前端挑戰:地球日版!

--- 標題:加入我們,迎接下一個前端挑戰:地球日版! 發表:真實 描述: 標籤: frontendchallenge、devchallenge、js、css 封面圖:https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emb626o0mysdsw32ox4k.png 使用 100:42 的比例可獲得最佳效果。 ===================== 發表於: 2024-04-17 14:14 +0000 =========================== --- 幾週前,我們開始了[第一個前端挑戰](https://dev.to/devteam/join-our-first-community-challenge-the-frontend-challenge-8be),並承諾如果社區喜歡參與,我們將定期舉辦這些挑戰 - 您的提交讓我們欣喜若狂,所以現在**我們又回來了**,我們的下一個前端挑戰! 對於下一個前端挑戰,我們將慶祝地球上最大的公民活動:**世界地球日**。 🌍🌏🌎 此挑戰有兩個提示。我們將為此挑戰帶回**CSS Art**和**Glam Up My Markup**提示 - 別擔心,One Byte Expander 將來會再次出現! 和上次一樣,每個提示都會有一個獲勝者,為了慶祝地球日,我們也將為此挑戰設置一個額外的獎品類別。這是贏得炫耀權、DEV 商店禮物和專屬 DEV 徽章的 3 次機會。與往常一樣,提交有效提交的參與者將獲得完成徽章。 *前端不是你的菜嗎?或者您正在尋找更大獎勵的挑戰? [Coze AI 機器人挑戰賽](https://dev.to/devteam/join-us-for-the-coze-ai-bot-challenge-3000-in-prizes-4dp7)現已開始,獎金池為 3,000 美元。* 繼續閱讀以了解每個提示以及如何參與! 提示 -- ### CSS 藝術:地球日 畫出您在地球日時想到的內容。這是我們美麗的星球嗎?它是提高人們對氣候變遷認識的象徵嗎?不管是什麼,告訴我們! 您提交的內容**不應使用任何 JavaScript** ,而應在 CSS 中發揮您的創造力。您提交的內容將包括標記,可能包括 SVG 等,但主要應該*展示*您的 CSS 技能。 **評審標準** - 創造力 - 有效使用CSS - 美感效果 這是供任何想要直接參與的人使用的提交模板,但請在提交之前查看[官方挑戰頁面](https://dev.to/challenges/frontend-2024-04-17)上的所有評審標準和挑戰規則。 {% cta https://dev.to/new?prefill=---%0Atitle%3A%20%0Apublished%3A%20%0Atags%3A%20frontendchallenge%2C%20devchallenge%2C%20css%0A---% 0A%0A\_This%20is%20a%20submission%20for%20%5BFrontend%20Challenge%20v24.04.17%5D(https%3A%2F%2Fdev.to%2Fdevteam%2Fjoin-us-for-the-next-frontend地球日版-52e4)%2C%20CSS%20Art%3A%20Earth%20Day.\_%0A%0A%23%23%20靈感%0A%3C!--%20What%20are%20you%20highlighting%20today% 3F %20--%3E%0A%0A%23%23%20Demo%20%0A%3C!--%20Show%20us%20your%20CSS%20Art!%20You%20can%20directly%20embed%20Art!%20You%20can%20directly%20embed%20an%20editor%20an%20editor%進入%20this%20post%20(參見%20the%20FAQ%20section%20of%20the%20challenge%20頁面)%20或%20you%20can%20share%20an%20image%20of%20your%20can%20share%20an%20image%20of%20your%20project%20% 20a%20public %20link%20到%20%20程式碼。 %2C%20what%20you %20已學會%2C%20anything%20you%20are%20尤其%20proud%20of%2C%20what%20you%20hope%20to%20do%20next%2C%20etc.%20--%3E %0A%0A%3C!-- %20Team%20Submissions%3A%20請%20pick%20one%20member%20to%20publish%20the%20submission%20and%20credit%20teammates%20by%20listing%20their%20DEV%20usernames%20directly %20in%20the%20body%20of%20the %20post.%20--%3E%0A%0A%3C!--%20We%20鼓勵%20you%20to%20考慮%20為%20your%20程式碼新增% 20a%20license%20。 %20想要)。 CSS 藝術挑戰提交模板 {% 結束%} ### 魅力我的標記:地球日慶祝活動登陸頁面 使用 CSS 和 JavaScript 使下面的入門 HTML 標記美觀、互動且有用。 您提交的內容應該比我們提供的 HTML 更有趣、更具互動性,而且還應該可用且易於存取。您不應直接編輯提供的 HTML,除非是透過 JavaScript。我們期待風格和實質。您可以加入基本樣板,包括元標記等以用於演示目的。 ``` <body> <header> <h1>Welcome to Our Earth Day Celebration!</h1> </header> <section> <article class="facts"> <h2>Did You Know?</h2> <p>Earth Day was first celebrated on April 22, 1970, and now includes a wide range of events coordinated globally by EARTHDAY.ORG including 1 billion people in more than 193 countries.</p> </article> <article> <h2>Why Celebrate Earth Day?</h2> <p>Earth Day is more than just a single day — April 22. It's a day to remind us to take action in our communities and beyond, to protect the environment, restore damaged ecosystems, and live a more sustainable life.</p> </article> <article> <h2>How You Can Help</h2> <p>Join us in making a difference! Here are some ways you can contribute to preserving our planet:</p> <ul> <li>Reduce, reuse, and recycle.</li> <li>Volunteer for cleanups in your community.</li> <li>Conserve water and electricity.</li> <li>Plant a tree.</li> <li>Educate others about environmental conservation.</li> </ul> </article> <div class="action-call"> <h2>Take Action Now</h2> <p>Join our Earth Day quiz to test your knowledge and learn more about what you can do to help our planet!</p> <a href="#">Start the Quiz!</a> </div> </section> <div class="testimonial"> <h2>Inspiration Corner</h2> <p>"The Earth does not belong to us: we belong to the Earth." - Marlee Matlin</p> <p>This Earth Day, let's remember we are part of a larger ecosystem and our actions have a profound impact on our planet.</p> </div> <div class="events"> <h2>Join an Event</h2> <p>Participate in local and global Earth Day events to take action towards a sustainable future. Check out <a href="#">events near you</a>.</p> </div> <footer> <p>Happy Earth Day! Together, we can make a difference.</p> </footer> </body> ``` **評審標準**: - 無障礙 - 可用性和使用者體驗 - 創造力 - 程式碼品質 這是供任何想要直接參與的人使用的提交模板,但請在提交之前查看[官方挑戰頁面](https://dev.to/challenges/frontend-2024-04-17)上的所有評審標準和挑戰規則。 {% cta https://dev.to/new?prefill=---%0Atitle%3A%20%0Apublished%3A%20%0Atags%3A%20devchallenge%2C%20frontendchallenge%2C%20css%2C%20javascript%2C%20frontendchallenge%2C%20css%2C%20javascript%0Ajava ---%0A%0A\_This%20is%20a%20submission%20for%20%5BFrontend%20Challenge%20v24.04.17%5D(https%3A%2F%2Fdev.to%2Fdevteam%2Fjoin-us-for-the-next前端挑戰-地球日-版本-52e4)%2C%20Glam%20Up%20My%20Markup%3A%20Earth%20Day%20Celebration%20Landing%20Page\_%0A%0A%23%23%20What%20I%20A0ABuilt% %3C!--%20告訴%20us%20什麼%20you%20built%20和%20what%20you%20是%20期待%20實現%20實現。 23%20示範%0A %3C!--%20Show%20us%20您的%20專案! 20the%20FAQ%20section%20from%20the%20challenge%20page )%20或%20you%20can%20share%20an%20image%20of%20your%20project%20and%20share%20a%20share%200%200%200%20share%程式碼。 20you%20are%20specially%20proud%20of%2C%20what%20you%20hope% 20至%20do%20next%2C%20等%20--%3E%0A%0A%3C!--%20團隊%20Submissions% 3A%20請%20pick%20one%20member%20至%20publish%20the%20submission%20and% 20credit%20teammates%20by%20listing%20their%20DEV%20usernames%20by%20listing%20their%20DEV%20usernames%20directthe%200%0%200inbody%200%200%200% %20--%3E%0A%0A%3C!--%20We%20encourage%20you% 20to%20考慮%20加入%20a%20許可證%20用於%20您的%20程式碼。 -%3E%0A%0A%3C! --%20Don%27t%20忘記%20to%20add%20a%20cover%20image%20to% 20您的%20貼文%20(如果%20您%20) 。 使我的標記提交模板更加迷人 {% 結束%} 附加獎類別 ----- 除了能夠贏得每個提示之外,我們還有一個特殊的獎品類別來紀念我們的星球: - 世界地球日:授予提高人們對氣候變遷認識的最佳提交作品。 除了前端挑戰賽獲勝者徽章和 DEV 商店贈送的禮物之外,我們的地球日獲勝者還將獲得一枚額外的超專屬徽章,用於展示其開發者檔案。 如何參與 ---- 為了參與,您需要使用提示的提交範本發布貼文。**您可以在[官方挑戰頁面](https://dev.to/challenges/frontend-2024-04-17)上找到所有評審標準、挑戰規則和提交範本。** 我們的規則和指南涵蓋了參賽要求、團隊提交、人工智慧的使用等主題,因此請務必仔細閱讀。 重要的日子 ----- 4 月 17 日:前端挑戰 v24.04.17 開始! 4 月 28 日:提交截止時間為太平洋夏令時間晚上 11:59 4 月 30 日:公佈得獎者 ![行星地球插圖](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExaDFxNGZ5Z2wwdGV4YXE5M2o0bGc2cWpuMDFlYnBpMmlwdXV3eWs0aSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l1KVcrdl7rJpFnY2s/giphy.gif) 我們很高興看到您的地球日專案!問題?請在下面詢問他們。 祝你好運,編碼愉快! --- 原文出處:https://dev.to/devteam/join-us-for-the-next-frontend-challenge-earth-day-edition-52e4

[小技巧分享] vue.js 動態替換 iframe src,如何解決 browser history 被修改問題

例如有個 component 如下: ``` vue <template> <iframe :src="url.src"></iframe> </template> <script> export default { data() { return { url: { src: 'https://example.com', }, }; }, }; </script> ``` 這時如果 src 網址變動,iframe 內會顯示新的網頁,同時也會造成 browser history 被修改,也就是點擊瀏覽器的上一頁時,會發現整個網頁沒有跳回上一頁,而是 iframe 回復到舊的網址,但如果這不是你想要的效果呢? vue.js 官方文件介紹 key 的時候提到: > It can also be used to force replacement of an element/component instead of reusing it. 所以答案就是在 iframe 加上動態的 key,key 和 src 同時變動時,vue.js 就會強制替換成新的 iframe,跳過 browser history 被修改的問題,點擊瀏覽器的上一頁就能正常回到前一頁了,範例如下: ``` vue <template> <iframe :key="url.key" :src="url.src"></iframe> </template> <script> export default { data() { return { url: { key: 1, src: 'https://example.com', }, }; }, }; </script> ``` P.S. 參考資料中,文章作者提到 react 也是一樣的處理方式。 參考資料: https://vuejs.org/api/built-in-special-attributes.html https://www.aleksandrhovhannisyan.com/blog/react-iframes-back-navigation-bug/ https://stackoverflow.com/questions/821359/reload-an-iframe-without-adding-to-the-history#answer-77278956

從頭開始實作 JavaScript 概念

在本文中,我們透過從頭開始建立幾個關鍵元件來探索 JavaScript 的基本建構塊。當我們深入研究這些概念時,我們將應用一系列從基礎到複雜的技術,使這種探索對於 JavaScript 世界的新手和專業人士都很有價值。 大綱 ---- - [`memoize()`](#memoize) - [`Array.map()`](#arraymap) - [`Array.filter()`](#arrayfilter) - [`Array.reduce()`](#arrayreduce) - [`bind()`](#bind) - [`call()` 、 `apply()`](#callapply) - [`setInterval()`](#setinterval) - [`cloneDeep()`](#clonedeep) - [`debounce()`](#debounce) - [`throttle()`](#throttle) - [`Promise`](#promise) - \[ `EventEmitter` ) <a name="memoize"></a> `memoize()` ----------- ### 任務說明 重新建立`memoize`函數(來自“lodash”),該函數透過快取函數呼叫的結果來優化效能。透過傳回快取的結果而不是重新計算,可以確保使用相同參數的重複函數呼叫更快。 ### 執行 ``` function customSerializer(entity, cache = new WeakSet()) { if (typeof entity !== 'object' || entity === null) { return `${typeof entity}:${entity}`; } if (cache.has(entity)) { return 'CircularReference'; } cache.add(entity); let objKeys = Object.keys(entity).sort(); let keyRepresentations = objKeys.map(key => `${customSerializer(key, cache)}:${ customSerializer(entity[key], cache) }` ); if (Array.isArray(entity)) { return `Array:[${keyRepresentations.join(',')}]`; } return `Object:{${keyRepresentations.join(',')}}`; } function myMemoize(fn) { const cache = new Map(); return function memoized(...args) { const keyRep = args.map(arg => customSerializer(arg) ).join('-'); const key = `${typeof this}:${this}-${keyRep}`; if (cache.has(key)) { return cache.get(key); } else { const result = fn.apply(this, args); cache.set(key, result); return result; } }; } ``` ### 實施的關鍵面 1. **快取機制:**它使用`Map`物件`cache`來儲存函數呼叫的結果。選擇`Map`物件是因為其高效率的鍵值配對和檢索功能。 2. **Custom Serializer** : `customSerializer`函數將函數參數轉換為用作快取鍵的字串表示形式。此序列化考慮了基本類型、物件(包括巢狀物件)、陣列和循環參考。對於物件和陣列,它們的鍵經過排序以確保一致的字串表示形式,無論屬性聲明順序如何。 3. **序列化`this`** : `this`的值指的是函數所屬的物件。在 JavaScript 中,方法可以根據呼叫它們的物件(即呼叫它們的上下文)而有不同的行為。這是因為`this`提供了對上下文物件的屬性和方法的存取,並且其值可能會根據函數的呼叫方式而變化。 4. **循環引用**:當物件直接或透過其屬性間接引用自身時,就會發生循環引用。這可能發生在更複雜的資料結構中,例如,物件`A`包含對物件`B`的引用,而物件`B`則直接或間接引用物件`A` 。處理循環引用以避免無限循環至關重要。 5. **使用`WeakSet`進行自動垃圾收集**: `WeakSet`保留對其物件的「弱」引用,這表示如果沒有其他引用, `WeakSet`中物件的存在不會阻止該物件被垃圾收集。此行為在需要臨時追蹤物件存在而又不會不必要地延長其生命週期的情況下特別有用。由於`customSerializer`函數可能只需要在序列化過程中標記物件的存取,而不儲存額外的資料,因此使用`WeakSet`可以確保物件不會僅僅因為它們在集合中的存在而保持活動狀態,從而防止潛在的內存洩漏。 <a name="arraymap"></a> `Array.map()` ------------- ### 任務說明 重新建立`Array.map()` ,它將轉換函數作為參數。此轉換函數將在陣列的每個元素上執行,並採用三個參數:當前元素、目前元素的索引和陣列本身。 ### 實施的關鍵面 1. **記憶體預先分配**: `new Array(this.length)`用於建立預先確定大小的陣列,以優化記憶體分配並透過避免加入元素時動態調整大小來提高效能。 ### 執行 ``` Array.prototype.myMap = function(fn) { const result = new Array(this.length); for (let i = 0; i < this.length; i++) { result[i] = fn(this[i], i, this); } return result; } ``` <a name="arrayfilter"></a> `Array.filter()` ---------------- ### 任務說明 重新建立`Array.filter()` ,它將謂詞函數作為輸入,迭代呼叫它的陣列的元素,將謂詞應用於每個元素。它傳回一個新陣列,僅包含謂詞函數傳回`true`元素。 ### 實施的關鍵面 1. **動態記憶體分配**:它動態地將符合條件的元素加入到`filteredArray`中,從而在很少有元素通過謂詞函數的情況下使該方法更有效地使用記憶體。 ### 執行 ``` Array.prototype.myFilter = function(pred) { const filteredArray = []; for (let i = 0; i < this.length; i++) { if (pred(this[i], i, this)) { filteredArray.push(this[i]); } } return filteredArray; } ``` <a name="arrayreduce"></a> `Array.reduce()` ---------------- ### 任務說明 重新建立`Array.reduce()` ,它對陣列的每個元素執行`reducer`函數,從而產生單一輸出值。 `reducer`函數有四個參數:累加器、currentValue、currentIndex 和整個陣列。 ### 實施的關鍵面 1. **`initialValue` value** : `accumulator`和`startIndex`會根據是否將`initialValue`作為參數傳遞來初始化。如果提供了`initialValue` (意味著`arguments.length`至少為`2` ),則`accumulator`設定為此`initialValue` ,並且迭代從第0個元素開始。否則,如果未提供`initialValue` ,則將陣列本身的第 0 個元素用作`initialValue` 。 ### 執行 ``` Array.prototype.myReduce = function(callback, initialValue) { let accumulator = arguments.length >= 2 ? initialValue : this[0]; let startIndex = arguments.length >= 2 ? 0 : 1; for (let i = startIndex; i < this.length; i++) { accumulator = callback(accumulator, this[i], i, this); } return accumulator; } ``` <a name="bind"></a> `bind()` -------- ### 任務說明 重新建立`bind()`函數,該函數允許將物件以及預先指定的初始參數(如果有)作為呼叫原始函數的上下文傳遞。它還應該支援`new`運算符的使用,從而能夠建立新實例,同時維護正確的原型鏈。 ### 執行 ``` Function.prototype.mybind = function(context, ...bindArgs) { const self = this; const boundFunction = function(...callArgs) { const isNewOperatorUsed = new.target !== undefined; const thisContext = isNewOperatorUsed ? this : context; return self.apply(thisContext, bindArgs.concat(callArgs)); }; if (self.prototype) { boundFunction.prototype = Object.create(self.prototype); } return boundFunction; }; ``` ### 實施的關鍵面 1. **處理`new` Operator** :語句`const isNewOperatorUsed = new.target !== undefined;`檢查是否透過`new`運算子將`boundFunction`作為建構函數呼叫。如果使用`new`運算符,則`thisContext`將設定為新建立的物件 ( `this` ) 而不是提供的`context` ,確認實例化應使用新的上下文而不是綁定期間提供的上下文。 2. **原型保留**:為了維護原始函數的原型鏈, `mybind`有條件地將`boundFunction`的原型設定為繼承自`self.prototype`的新物件。此步驟確保從`boundFunction` (用作建構函數時)建立的實例正確地繼承原始函數原型的屬性。此機制保留了預期的繼承層次結構並維護instanceof 檢查。 ### 將`bind()`與`new`一起使用的範例 讓我們考慮一個簡單的建構函數,它建立代表汽車的物件: ``` function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } ``` 想像一下,我們常常創造「豐田」品牌的`Car`物件。為了讓這個過程更有效率,我們可以使用`bind`為Toyotas建立一個專門的建構函數,預先填入`make`參數: ``` // Creating a specialized Toyota constructor with 'Toyota' // as the pre-set 'make' const ToyotaConstructor = Car.bind(null, 'Toyota'); // Now, we can create Toyota car instances // without specifying 'make' const myCar = new ToyotaConstructor('Camry', 2020); // Output: Car { make: 'Toyota', model: 'Camry', year: 2020 } console.log(myCar); ``` <a name="callapply"></a> `call()` 、 `apply()` -------------------- ### 任務說明 重新建立`call()`和`apply()`函數,它們允許使用給定的 this 值和單獨提供的參數來呼叫函數。 ### 執行 ``` Function.prototype.myCall = function(context, ...args) { const fnSymbol = Symbol('fnSymbol'); context[fnSymbol] = this; const result = context[fnSymbol](...args); delete context[fnSymbol]; return result; }; Function.prototype.myApply = function(context, args) { const fnSymbol = Symbol('fnSymbol'); context[fnSymbol] = this; const result = context[fnSymbol](...args); delete context[fnSymbol]; return result; }; ``` ### 實施的關鍵面 1. **屬性命名的符號用法**:為了防止覆蓋上下文物件上潛在的現有屬性或由於名稱衝突而導致意外行為,使用唯一的`Symbol`作為屬性名稱。這確保了我們的臨時屬性不會幹擾上下文物件的原始屬性。 2. **執行後清理**:函數呼叫執行後,新增到上下文物件中的臨時屬性將被刪除。此清理步驟對於避免在上下文物件上留下修改後的狀態至關重要。 <a name="setinterval"></a> `setInterval()` --------------- ### 任務說明 使用`setTimeout`重新建立`setInterval` 。此函數應以指定的時間間隔重複呼叫提供的回呼函數。它會傳回一個函數,當呼叫該函數時,該函數會停止間隔。 ### 執行 ``` function mySetInterval(callback, interval) { let timerId; const repeater = () => { callback(); timerId = setTimeout(repeater, interval); }; repeater(); return () => { clearTimeout(timerId); }; } ``` ### 實施的關鍵面 1. **取消功能**: `mySetInterval`傳回的函數提供了一種簡單直接的方法來取消正在進行的間隔,而無需在函數範圍之外公開或管理計時器 ID。 <a name="clonedeep"></a> `cloneDeep()` ------------- ### 任務說明 重新建立執行給定輸入的深度複製的`cloneDeep`函數(來自“lodash”)。該函數應該能夠複製複雜的資料結構,包括物件、陣列、映射、集合、日期和正規表示式,並保持每個元素的結構和類型完整性。 ### 執行 ``` function myCloneDeep(entity, map = new WeakMap()) { if (entity === null || typeof entity !== 'object') { return entity; } if (map.has(entity)) { return map.get(entity); } let cloned; switch (true) { case Array.isArray(entity): cloned = []; map.set(entity, cloned); cloned = entity.map(item => myCloneDeep(item, map)); break; case entity instanceof Date: cloned = new Date(entity.getTime()); break; case entity instanceof Map: cloned = new Map(Array.from(entity.entries(), ([key, val]) => [myCloneDeep(key, map), myCloneDeep(val, map)])); break; case entity instanceof Set: cloned = new Set(Array.from(entity.values(), val => myCloneDeep(val, map))); break; case entity instanceof RegExp: cloned = new RegExp(entity.source, entity.flags); break; default: cloned = Object.create( Object.getPrototypeOf(entity)); map.set(entity, cloned); for (let key in entity) { if (entity.hasOwnProperty(key)) { cloned[key] = myCloneDeep(entity[key], map); } } } return cloned; } ``` ### 實施的關鍵面 1. **循環引用處理**:利用`WeakMap`來追蹤已存取的物件。如果遇到已經克隆的物件,則返回先前克隆的物件,有效處理循環參考並防止堆疊溢位錯誤。 2. **特殊物件的處理**:區分幾種物件類型( `Array` 、 `Date` 、 `Map` 、 `Sets` 、 `RegExp` ),以確保每種類型都被適當地克隆,並保留其特定特徵。 ``` - **`Array`**: Recursively clones each element, ensuring deep cloning. ``` ``` - **`Date`**: Copies the date using its numeric value (timestamp). ``` ``` - **Maps and Sets**: Constructs a new instance, recursively cloning each entry (for `Map`) or value (for `Set`). ``` ``` - **`RegExp`**: Clones by creating a new instance with the source and flags of the original. ``` 3. **物件屬性的複製**:當輸入是普通物件時,它會建立一個與原始物件具有相同原型的物件,然後遞歸地複製每個自己的屬性,在保持原型鏈的同時確保深度克隆。 4. **效率和性能**:利用`WeakMap`進行記憶,有效處理具有重複引用和循環的複雜大型結構,透過避免冗餘克隆來確保最佳性能。 <a name="debounce"></a> `debounce()` ------------ ### 任務說明 重新建立`debounce`函數(來自“lodash”),它允許限制給定回調函數觸發的頻率。當在短時間內重複呼叫時,在指定的延遲後僅執行最後一次呼叫。 ``` function myDebounce(func, delay) { let timerId; const debounced = function(...args) { clearTimeout(timerId); timerId = setTimeout(() => { func.apply(this, args); }, delay); }; debounced.cancel = function() { clearTimeout(timerId); timerId = null; }; debounced.flush = function() { clearTimeout(timerId); func.apply(this, arguments); timerId = null; }; return debounced; } ``` ### 實施的關鍵面 1. **取消功能**:引入`.cancel`方法使外部控制能夠取消去抖函數的任何暫停執行。這增加了靈活性,允許響應特定事件或條件而取消去抖功能。 2. **透過 Flush 立即執行**: `.flush`方法允許立即執行去抖函數,而不考慮延遲。這在需要確保立即應用去抖函數的效果的情況下非常有用,例如,在卸載元件或完成互動之前。 <a name="throttle"></a> `throttle()` ------------ ### 任務說明 重新建立`throttle`函數(來自“lodash”),它確保給定的回調函數在每個指定的時間間隔內最多只呼叫一次(在我們的例子中是在開始時)。與去抖動不同,限制保證函數會定期執行,確保進行更新,儘管更新速度是受控的。 ### 執行 ``` function myThrottle(func, timeout) { let timerId = null; const throttled = function(...args) { if (timerId === null) { func.apply(this, args) timerId = setTimeout(() => { timerId = null; }, timeout) } } throttled.cancel = function() { clearTimeout(timerId); timerId = null; }; return throttled; } ``` ### 實施的關鍵面 1. **取消功能**:引入`.cancel`方法可以清除節流計時器的任何計劃重置。這在清理階段非常有用,例如 UI 庫/框架中的元件卸載,以防止過時的執行並有效管理資源。 <a name="promise"></a> `Promise` --------- ### 任務說明 重新建立`Promise`類別。它是為非同步程式設計的構造,允許暫停程式碼的執行,直到非同步進程完成。從本質上講,承諾代表了在其建立時不一定已知的值的代理。它允許您將處理程序與非同步操作的最終成功值或失敗原因相關聯。這使得非同步方法可以像同步方法一樣傳回值:非同步方法不是立即傳回最終值,而是傳回一個在未來某個時刻提供該值的承諾。 `Promise`包含處理已完成和拒絕狀態的方法( `then` 、 `catch` ),以及無論結果如何都執行程式碼的方法( `finally` )。 ``` class MyPromise { constructor(executor) { ... } then(onFulfilled, onRejected) { ... } catch(onRejected) { ... } finally(callback) { ... } } ``` ### `constructor`實現 ``` constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onFulfilledCallbacks.forEach(fn => fn()); } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach(fn => fn()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } ``` ### `constructor`實現的關鍵方面 1. **狀態管理**:以「待處理」狀態初始化。解決時切換為“已完成”,被拒絕時切換為“拒絕”。 2. **值和原因**:保存承諾的最終結果( `value` )或拒絕的原因( `reason` )。 - **處理非同步**:接受包含非同步操作的`executor`函數。 `executor`採用兩個函數, `resolve`和`reject` ,當呼叫它們時,將promise轉換到對應的狀態。 3. **回呼陣列**:維護回呼佇列( `onFulfilledCallbacks` 、 `onRejectedCallbacks` ),以用於等待解決或拒絕承諾的延遲操作。 ### `.then`實施 ``` resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError( 'Chaining cycle detected for promise')); } if (x instanceof MyPromise) { x.then(resolve, reject); } else { resolve(x); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }; let promise2 = new MyPromise((resolve, reject) => { if (this.state === 'fulfilled') { setTimeout(() => { try { let x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } else if (this.state === 'rejected') { setTimeout(() => { try { let x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } else if (this.state === 'pending') { this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); }); } }); return promise2; } ``` ### `.then`實施的關鍵方面 1. **預設處理程序**:將非函數處理程序轉換為標識函數(用於實現)或拋出程序(用於拒絕),以確保承諾鏈中的正確轉發和錯誤處理。 2. **Promise 連結**: `then`方法允許連結 Promise,從而實現順序非同步操作。它會建立一個新的 Promise ( `promise2` ),該 Promise 取決於傳遞給它的回呼函數 ( `onFulfilled` 、 `onRejected` ) 的結果。 3. **處理解決方案和拒絕**:僅在當前承諾解決(履行或拒絕)後才會呼叫所提供的回調。每個回呼的結果 ( `x` ) 可能是一個值或另一個 Promise,決定了`promise2`的解析。 4. **防止連結循環**: `resolvePromise`函數檢查`promise2`是否與結果 ( `x` ) 相同,避免 Promise 等待自身的循環,從而導致`TypeError` 。 5. **支援 MyPromise 和 Non-Promise 值**:如果結果 ( `x` ) 是`MyPromise`的實例, `then`使用其解析或拒絕來解決`promise2` 。此功能支援基於 Promise 的操作的無縫集成,無論是來自`MyPromise`實例還是本機 JavaScript Promise,假設它們具有相似的行為。對於非 Promise 值,或當`onFulfilled`或`onRejected`只是傳回一個值時, `promise2`將使用該值進行解析,從而在 Promise 鏈中實現簡單的轉換或分支邏輯。 6. **非同步執行保證**:透過使用`setTimeout`延遲`onFulfilled`和`onRejected`的執行, `then`確保非同步為。此延遲保持一致的執行順序,確保`onFulfilled`和`onRejected`在執行堆疊清除後呼叫。 7. **錯誤處理**:如果`onFulfilled`或`onRejected`內發生異常, `promise2`會因錯誤而被拒絕,從而允許錯誤處理通過 Promise 鏈傳播。 ### `catch`並`finally`實現 ``` static resolve(value) { if (value instanceof MyPromise) { return value; } return new MyPromise((resolve, reject) => resolve(value)); } catch(onRejected) { return this.then(null, onRejected); } finally(callback) { return this.then( value => MyPromise.resolve(callback()) .then(() => value), reason => MyPromise.resolve(callback()) .then(() => { throw reason; }) ); } ``` ### `.catch`實施的關鍵面向: 1. **簡化的錯誤處理:** `.catch`方法是`.then(null, onRejected)`的簡寫,專門專注於處理拒絕場景。當只需要拒絕處理程序時,它允許更清晰的語法,從而提高程式碼的可讀性和可維護性。 2. **Promise Chaining 支援:**由於它在內部委託給`.then` ,所以`.catch`返回一個新的 Promise,從而保持 Promise 鏈功能。這允許在錯誤恢復或透過重新拋出或返回新的被拒絕的承諾傳播錯誤後繼續進行鏈操作。 3. **錯誤傳播:**如果提供了`onRejected`並且執行時沒有錯誤,則傳回的 Promise 將使用`onRejected`的傳回值進行解析,從而有效地允許 Promise 鏈中的錯誤復原。如果`onRejected`拋出錯誤或傳回被拒絕的 Promise,則錯誤會沿著鏈傳播。 ### `.finally`實現的關鍵面向: 1. **始終執行:** `.finally`方法確保執行提供的`callback` ,無論 Promise 是履行還是拒絕。這對於需要在非同步操作之後發生的清理操作特別有用,與其結果無關。 2. **傳回值保留:**雖然`.finally`中的`callback`不接收任何參數(與`.then`或`.catch`不同),但 Promise 的原始履行值或拒絕原因將被保留並透過鏈傳遞。從`.finally`傳回的 Promise 會以相同的值或原因被解析或拒絕,除非`callback`本身導致被拒絕的 Promise。 3. **錯誤處理與傳播:**如果`callback`執行成功, `.finally`傳回的 Promise 將按照與原始 Promise 相同的方式進行結算。但是,如果`callback`拋出錯誤或返回被拒絕的 Promise,則從`.finally`返回的 Promise 會因這個新錯誤而被拒絕,從而允許錯誤攔截並更改 Promise 鏈中的拒絕原因。 <a name="eventemitter"></a> `EventEmitter` -------------- ### 任務說明 重新建立`EventEmitter`類,該類別允許實現觀察者模式,使物件(稱為「發射器」)能夠發出命名事件,從而導致呼叫先前註冊的偵聽器(或「處理程序」)。這是 Node.js 中用於處理非同步事件的關鍵元件,廣泛用於發出訊號以及管理應用程式狀態和行為。實作自訂`EventEmitter`涉及建立用於註冊事件偵聽器、觸發事件和刪除偵聽器的方法。 ``` class MyEventEmitter { constructor() { this.events = {}; } on(eventName, listener) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(listener); } once(eventName, listener) { const onceWrapper = (...args) => { listener.apply(this, args); this.off(eventName, onceWrapper); }; this.on(eventName, onceWrapper); } emit(eventName, ...args) { const listeners = this.events[eventName]; if (listeners && listeners.length) { listeners.forEach((listener) => { listener.apply(this, args); }); } } off(eventName, listenerToRemove) { if (!this.events[eventName]) { return; } const filterListeners = (listener) => listener !== listenerToRemove; this.events[eventName] = this.events[eventName].filter(filterListeners); } } ``` ### `EventEmitter`實現的關鍵面 1. **EventListener Registration `.on` :**將偵聽器函數新增至指定事件的偵聽器陣列中,如果該事件名稱尚不存在則建立一個新陣列。 2. **一次性事件偵聽器`.once` :**註冊一個偵聽器,該偵聽器在呼叫一次後會自行刪除。它將原始偵聽器包裝在一個函數 ( `onceWrapper` ) 中,該函數也會在執行後刪除包裝器,確保偵聽器僅觸發一次。 3. **發出事件`.emit` :**觸發事件,使用提供的參數呼叫所有已註冊的偵聽器。它將參數應用於每個偵聽器函數,從而允許將資料傳遞給偵聽器。 4. **刪除事件偵聽器`.off` :**從事件偵聽器陣列中刪除特定偵聽器。如果事件在刪除後沒有偵聽器,則可以將其保留為空陣列或可選地進一步清理(此實作中未顯示)。 --- 原文出處:https://dev.to/antonzo/implementing-javascript-concepts-from-scratch-4623

成長最快的 5 個 JavaScript Repo

1億個 Repo ======= GitHub 儲存庫數量龐大,實際上超過 1 億個。 ![https://media3.giphy.com/media/26ufdipQqU2lhNA4g/giphy.gif?cid=7941fdc6opu42na4bummzjiknliafzb2p1jiqj8y008lvjce&ep=v1_jiknliafzb2p1jiqj8y008行](https://media3.giphy.com/media/26ufdipQqU2lhNA4g/giphy.gif?cid=7941fdc6opu42na4bummzjiknliafzb2p1jiqj8y008lvjce&ep=v1_gifs_search&rid=giphy.gif&ct=g) 那你怎麼知道哪些值得一看呢? 嗯,就像我們好奇的任何事情一樣,我們通常會向同行詢問他們看重什麼。 *你好朋友,* - *最近有聽什麼好聽的新音樂嗎?* - *您最喜歡城裡哪些餐廳?我需要嘗試一些新的地方。* - *我很快就要去健行,我需要一些好的鞋子推薦!* 因此,當嘗試對成長最快的 GitHub 儲存庫進行排名時,了解開發人員最感興趣的儲存庫是有意義的。這正是[ROSS 指數](https://runacap.com/ross-index/)。這是過去一年成長最快的開源新創公司的綜合清單! 下面讓我們深入探討一下。 誰上榜了? ===== ![羅斯_頂部_50](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3ripm7am46ljul6nssp.png) ROSS Index 在將儲存庫新增至其喜歡的清單時使用一些標準: - 今年年初就有超過 1000 顆星 - 它不是 10 年前建立的 - 它背後的公司仍然是一家新創公司(不是微軟或其他大公司) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/znfb3nk7j2rxrrb0r2pb.png) 制定此標準的原因是因為他們正在開發者世界中尋找令人興奮的新發展和趨勢以及投資機會。 很酷的是,這也讓我們的開發人員能夠很好地了解我們的環境和工具正在如何變化,以及哪些新趨勢開始真正獲得動力。 我們已經繼續瀏覽了列表並挑選了頂級 JavaScript/TypeScript 存儲庫,並了解了一些關於它們是什麼以及它們如何工作的訊息,因此您不必這樣做。 順便說一句,根據 GitHub Star 計數,下面所有這些 JS/TS 儲存庫去年**增長了至少 400%** 。這是巨大的,這意味著開發人員真的很喜歡它們! 1. [LangChain](https://langchain.com) — 建構強大的人工智慧聊天機器人 ====================================================== ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s44qj4xi31dauqisitsg.png) 去年榜單上的大贏家是[浪鏈](https://js.langchain.com/)。您可能已經嘗試過使用OpenAI 的API 在自己的應用程式中獲取ChatGPT 的答案,但如果您想開始在像ChatGPT 這樣的LLM(大型語言模型)之上建立真正複雜的應用程式,那麼您應該查看LangChain ! LangChain 是一個完整的庫和框架,可以更有效地與法學碩士合作。假設您想要授予 ChatGPT 存取維基百科文章、當前天氣和您的 Gmail 帳戶的權限,以便您可以讓它根據所有這些資訊為您編寫和發送電子郵件。嗯,LangChain 擁有建造這個所需的所有元件! --- 順便提一句。如果您對學習如何在自己的應用程式中使用 LLM 感到好奇,請查看[CoverLetterGPT,這是一個很棒的開源儲存庫](https://github.com/vincanger/coverlettergpt),它向您展示如何將工作描述和簡歷的PDF 轉換為可立即自訂的求職信! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/33h1jj9aof35g380hobd.png) 2. [Wasp](https://github.com/wasp-lang/wasp) — 使用 React 和 Node.js 建立全端 Web 應用程式的最快方法 ==================================================================================== ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvqj3vx1kpvk7l92zc9f.png) [Wasp](https://github.com/wasp-lang/wasp) (嘿,這就是我們!)一直致力於讓全端 Web 應用程式開發變得更簡單、更快速、更有趣,讓大量開發人員受益。 ![黃蜂見證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3mcpbfbbrmqd8ixory3.png) Wasp 允許開發人員只在設定檔中定義某些功能,從而使他們免於編寫大量樣板檔案。一旦完成,Wasp 就會處理剩下的事情。 這意味著 Wasp 用戶可以免費獲得所有這些以及更多內容: - 🔐 電子郵件驗證、Google 或 GitHub Auth 以及 UI 元件 - 🧷 全端式安全, - 📧 電子郵件發送, - ⛏ 非同步(cron)作業, - 📝 React Query 支援資料獲取, - 🚨 安全最佳實踐, - 🧭 客戶端和伺服器路由 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/385i7biizded02qwbw0u.png) 如果您正在尋找一種很酷的方式來開始使用 Wasp,請查看[Open SaaS](https://github.com/wasp-lang/open-saas) ,這是一個使用 Wasp 建置的完全免費、開源的 SaaS 入門工具。或者,您可以嘗試[MAGE](https://usemage.ai) ,這是一個 AI 應用程式生成器,它利用 Wasp 的強大功能,透過簡單的提示即可建立全端 Web 應用程式程式碼庫! 3.[重新發送](https://resend.com)-重新思考開發者電子郵件發送 ========================================== ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ouqdejzdcmj8jyatiz9k.png) Resend 是一個非常靈活的開發人員電子郵件API 和儀表板,允許用戶管理交易和行銷電子郵件,這意味著他們可以做很酷的事情,例如檢查他們發送的電子郵件是否已被收件人打開,或移至垃圾郵件! Resend 也是非常流行的[React Email 儲存庫的](https://github.com/resend/react-email)幕後黑手,該儲存庫擁有超過 12k 顆星,並且是一個客戶端元件庫,可以使樣式設計和發送漂亮的電子郵件變得更加容易。 現在,您不必從您的應用程式發送看起來像是 1995 年編碼的電子郵件! ![https://media1.giphy.com/media/lcYkeZa1gBCzS/giphy.gif?cid=7941fdc6zjvxaju8vklzbp67owj0qve9yxtkglufhjtxvv6x&ep=v1_gifs_search&rid&rid=giphy.](https://media1.giphy.com/media/lcYkeZa1gBCzS/giphy.gif?cid=7941fdc6zjvxaju8vklzbp67owj0qve9yxtkglufhjtxvv6x&ep=v1_gifs_search&rid=giphy.gif&ct=g) 4. [Nebuly](https://www.nebuly.com/) — AI 聊天機器人的使用者體驗訊息 ======================================================= ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uudvu9g07tjmz5cghi14.png) 隨著法學碩士和人工智慧聊天機器人的興起,出現了一系列與它們相關的有趣工具。 [Nebuly](https://www.nebuly.com/)就是這樣一種工具,它允許開發人員和團隊監控使用者如何與聊天機器人互動。 作為一個開源專案,它可以自行部署並整合到您的應用程式(可能是您使用 LangChain 建立的)中,以便您可以看到: - 您的用戶問得最多的是什麼 - 深入探討對話主題 - 建立實驗和 A/B 測試 - 查看哪些內容不適合您的用戶 這種工具幫助企業和 SaaS 應用程式深入了解客戶需求的潛力是巨大的,因此難怪這是另一個成長最快的儲存庫! ### 5. [Formbricks](https://formbricks.com/) — 輕鬆獲得使用者的回饋 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/znogvgouf3idge592084.png) [Formbricks](https://formbricks.com/)將自己定位為開源 Typeform 替代品,它允許您輕鬆建立表單並將其嵌入到您的應用程式中。 作為一個開源產品,您可以獲得慷慨的免費套餐,允許您建立與您的應用程式風格相匹配的專業表單,允許您監控您的調查資料,甚至將其整合到您可能使用的其他工具中,例如Notion、 Zapier,或Google表格。 如果您想收集使用者體驗資訊並正在尋找開源解決方案,這非常有用! 成長快、成長強 ======= 開源新創公司和解決方案的世界正在快速發展,隨著人們對開源解決方案的興趣越來越大,生態系統也變得越來越強大。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfiduc03hfxb5qhe7xse.gif) 我們希望您喜歡這篇對 2023 年以來增長最快的 5 個開源 JavaScript/TypeScript 存儲庫的總結。如果有您了解並喜愛但此處未提及的開源解決方案,請告訴我們!誰知道呢,也許開發者也會喜歡它,並且它會出現在明年的清單中 🙂 --- 原文出處:https://dev.to/wasp/top-5-fastest-growing-javascript-repos-92n

如何建構:人工智慧驅動的部落格平台(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

終於有人修復了 Javascript

JavaScript 生態系統正以驚人的速度發展。當您熟悉某種技術時,就會出現大量新方法。其中一些(例如 TypeScript)獲得了廣泛採用,而另一些(例如 CoffeeScript)則悄悄消失。每項創新最初都會引起人們的興奮,但隨著時間的推移,社區經常分裂,批評者最終會產生自己的框架。這種無止盡的循環讓我對聲稱可以解決所有問題的最新「神奇」框架越來越警惕。我已經從尋求工具作為解決方案轉變為擁抱對模式的理解,而不是不斷追求新技術。 這就是為什麼我向您指出針對 TypeScript 專案的特殊工具,不僅僅是另一個工具,而是鼓勵良好實踐的範例: [Effect](https://effect.website/) 。 讓我們來看看為什麼你應該踏出這一步。 彩色函數 ---- 您是否曾經問過自己,[您的功能是什麼顏色?](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/) 讓我為您總結一下。想像一下您的程式碼庫中有藍色和紅色函數。規則很簡單:您可以在藍色函數中使用紅色函數,但反之則不行。那不是一場惡夢嗎?現在用“async”替換藍色。是的,你在 Javascript 得到了函數著色。 那我們該如何對抗這種著色問題呢?如果我們想刪除彩色函數,我們需要建立某種包裝器,僅在需要時使用 Promise。例如「未來」還是…「效果」? ``` import { Effect, pipe } from "effect"; const fibonacci = (a: number): Effect.Effect<number> => a <= 1 ? Effect.succeed(a) : pipe( Effect.all([fibonacci(a - 1), fibonacci(a - 2)]), Effect.map(([a, b]) => a + b) ); await Effect.runPromise(fibonacci(10)); ``` 使用`Effect`與`Promise`主要差異在於如何處理並發。 Effect 提供了 Fiber,它是類似於綠色線程或 goroutine 的輕量級並發結構。此功能允許我們在不阻塞主執行緒的情況下執行長時間執行或非同步任務,即使在傳統的同步函數中也可以啟動主執行緒。 ``` import { Effect, Console, pipe } from "effect"; const longRunningTask = pipe( Console.log("Start of long running task"), Effect.delay(1000), Effect.tap(Console.log("End of long running task")) ); console.log("Start of program"); Effect.runFork(longRunningTask); console.log("End of program"); /** * OUTPUT: * Start of program * End of program * Start of long running task * End of long running task */ ``` 雖然Effect 並沒有消除JavaScript 中固有的非同步/同步差異(函數著色),但透過使用纖程處理非同步操作,它允許同步函數呼叫非同步效果,而不會使其本身成為非同步,從而在很大程度上緩解“著色”問題。 類型安全錯誤 ------ 我們來看看這個函數: ``` const divide = (a: number, b: number) => a / b; ``` 我們這裡剛剛引入了一個問題,我們不能除以零。那麼讓我們稍微重構一下程式碼: ``` const divide = (a: number, b: number) => { if (b === 0) throw new Error('Cannot divide by zero.'); return a / b; } ``` 你覺得不錯嗎?它不是。因為它不是類型安全的。想要使用您的函數的人不會知道您的函數可能會拋出異常。對於像這樣的簡單函數來說,這可能看起來微不足道,但是當您有數十個潛在錯誤時,它可能會變成一場噩夢。其他較成熟的語言有諸如`Either`或`Result`之類的概念來表示類型安全錯誤。看起來像這樣: ``` type Result<T, E> = Ok<T> | Err<E>; // With something like: type Ok<T> = { kind: "Ok", data: T }; type Err<E> = { kind: "Err", err: E }; ``` 使用 Effect,您將擁有開箱即用的功能: `Effect<T, E>` 。您不必問自己在執行過程中會發生什麼樣的錯誤,您可以直接從函數簽名中知道它。它還附帶幫助函數來從錯誤中恢復。 ``` const divide = (a: number, b: number): Effect<number, "DivisionByZeroError"> => { if (b === 0) return Effect.fail("DivisionByZeroError"); return Effect.succeed(a / b); } ``` 新類型或品牌類型 -------- 你知道,回顧我以前的職能,我意識到我們可以做得更好。 ``` const divide = (a: number, b: NonZeroNumber) => ... ``` 那麼如何定義`NonZeroNumber`呢?如果您只是`type NonZeroNumber = number`它不會阻止人們用「0」來呼叫它。有一個模式:新類型。是的,Effect 也支持這一點: ``` import { Brand } from "effect" type NonZeroNumber = number & Brand.Brand<"NonZeroNumber"> const NonZeroNumber = Brand.refined<NonZeroNumber>( (n) => n !== 0, // Check if the value is a non-zero number (n) => Brand.error(`Expected ${n} to be a non-zero number`) ) ``` 這樣,您就知道您的函數**不能**使用任何數字來呼叫:它需要一種不包括零的特殊類型的數字。 依賴注入 ---- 如果您想遵循「控制反轉」原則,您可能需要研究「依賴注入」。這個概念非常簡單:函數應該能夠從自己的上下文中存取它所需要的內容。 ``` // With a singleton const read = (filename) => FileReader.read(filename); // With dependency injection const read = (reader: FileReader) => (filename) => reader.read(filename); ``` 出於多種原因,最好這樣做,例如解耦事物、允許輕鬆測試、具有不同的上下文等。 雖然有幾個框架可以幫助實現這一點,但 Effect 確實透過簡化來粉碎它:將依賴項作為 Effect 的第三個參數。 ``` const read = (filename): Effect<File, Error, FileReader> => { return Effect.flatMap(FileReader, fileReader => { return fileReader.read(filename); }) } ``` 結論 -- 您應該考慮 Effect 的原因還有很多。當然,一開始並不容易,您必須學習以不同的方式編碼。但與許多讓你學習「他們的」做事方式的框架相反,Effect 實際上教你好的模式,這些模式已經在其他語言中得到了證明。實際上,Effect 很大程度上受到了 Scala 中的 ZIO 的啟發,而 Scala 本身也受到了 Haskell 的啟發,而 Haskell 至今仍被認為是良好程式模式的頂峰之一。 --- 原文出處:https://dev.to/almaju/someone-finally-fixed-javascript-426i

您必須了解的 21 個 HTML 技巧

在這篇文章中,我將分享 21 個帶有程式碼片段的 HTML 技巧,可以提高您的編碼技能。 讓我們直接進入正題吧。🚀 建立聯絡連結 ------ 使用 HTML 建立可點擊的電子郵件、電話和簡訊連結: ``` <!-- Email link --> <a href="mailto:[email protected]"> Send Email </a> <!-- Phone call link --> <a href="tel:+1234567890"> Call Us </a> <!-- SMS link --> <a href="sms:+1234567890"> Send SMS </a> ``` 建立可折疊內容 ------- 當您想要在網頁上包含可折疊內容時,可以使用`<details>`和`<summary>`標記。 `<details>`標籤建立隱藏內容的容器,而`<summary>`標籤提供可點擊的標籤來切換該內容的可見性。 ``` <details> <summary>Click to expand</summary> <p>This content can be expanded or collapsed.</p> </details> ``` 利用語意元素 ------ 為您的網站選擇語義元素而不是非語義元素。它們使您的程式碼變得有意義,並改善結構、可存取性和 SEO。 ![HTML 語意與非語意元素](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqmm5d3vvw5fvrqgz861.jpg) 將表單元素分組 ------- 使用`<fieldset>`標記對表單中的相關元素進行分組,並使用`<legend>`標記和`<fieldset>`來定義`<fieldset>`標記的標題。 這對於建立更有效率、更易於存取的表單非常有用。 ``` <form> <fieldset> <legend>Personal details</legend> <label for="firstname">First name:</label> <input type="text" id="firstname" name="firstname" /> <label for="email">Email:</label> <input type="email" id="email" name="email" /> <label for="contact">Contact:</label> <input type="text" id="contact" name="contact" /> <input type="button" value="Submit" /> </fieldset> </form> ``` 增強下拉式選單 ------- 您可以使用`<optgroup>`標籤對`<select>` HTML 標籤中的相關選項進行分組。 當您使用大型下拉式選單或長選項清單時可以使用此功能。 ``` <select> <optgroup label="Fruits"> <option>Apple</option> <option>Banana</option> <option>Mango</option> </optgroup> <optgroup label="Vegetables"> <option>Tomato</option> <option>Broccoli</option> <option>Carrot</option> </optgroup> </select> ``` 改進視訊演示 ------ `poster`屬性可以與`<video>`元素一起使用來顯示圖像,直到使用者播放影片。 ``` <video controls poster="image.png" width="500"> <source src="video.mp4" type="video/mp4 /> </video> ``` 支援多項選擇 ------ 您可以將`multiple`屬性與`<input>`和`<select>`元素一起使用,以允許使用者一次選擇/輸入`multiple`值。 ``` <input type="file" multiple /> <select multiple> <option value="java">Java</option> <option value="javascript">JavaScript</option> <option value="typescript">TypeScript</option> <option value="rust">Rust</option> </select> ``` 將文字顯示為下標和上標 ----------- `<sub>`和`<sup>`元素可用於分別將文字顯示為下標和上標。 ![HTML <sub> 和 <sup> 元素](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqk487tb0jufx8jmgpaf.jpg) 建立下載連結 ------ 您可以使用帶有`<a>`元素的`download`屬性來指定當使用者點擊連結時,應下載而不是導航到連結的資源。 ``` <a href="document.pdf" download="document.pdf"> Download PDF </a> ``` 定義相對連結的基本 URL ------------- 您可以使用`<base>`標籤來定義網頁中所有相對 URL 的基本 URL。 當您想要為網頁上的所有相對 URL 建立共用起點時,這會很方便,從而更輕鬆地導航和載入資源。 ``` <head> <base href="https://shefali.dev" target="_blank" /> </head> <body> <a href="/blog">Blogs</a> <a href="/get-in-touch">Contact</a> </body> ``` 控制圖像加載 ------ `<img>`元素的`loading`屬性可用來控制瀏覽器載入圖片的方式。它有三個值:「eager」、「lazy」和「auto」。 ``` <img src="picture.jpg" loading="lazy"> ``` 管理翻譯功能 ------ 您可以使用`translate`屬性來指定元素的內容是否應由瀏覽器的翻譯功能來翻譯。 ``` <p translate="no"> This text should not be translated. </p> ``` 設定最大輸入長度 -------- 透過使用`maxlength`屬性,您可以設定使用者在輸入欄位中輸入的最大字元數。 ``` <input type="text" maxlength="4"> ``` 設定最小輸入長度 -------- 透過使用`minlength`屬性,您可以設定使用者在輸入欄位中輸入的最小字元數。 ``` <input type="text" minlength="3"> ``` 啟用內容編輯 ------ 使用`contenteditable`屬性指定元素的內容是否可編輯。 它允許使用者修改元素內的內容。 ``` <div contenteditable="true"> You can edit this content. </div> ``` 控制拼字檢查 ------ 您可以`spellcheck`屬性與`<input>`元素、內容可編輯元素和`<textarea>`元素結合使用,以啟用或停用瀏覽器的拼字檢查。 ``` <input type="text" spellcheck="true"/> ``` 確保無障礙 ----- `alt`屬性指定圖像無法顯示時的替代文字。 始終包含圖像的描述性 alt 屬性,以提高可存取性和 SEO。 ``` <img src="picture.jpg" alt="Description for the image"> ``` 定義連結的目標行為 --------- 您可以使用`target`屬性來指定您按一下連結資源時將顯示的位置。 ``` <!-- Opens in the same frame --> <a href="https://shefali.dev" target="_self">Open</a> <!-- Opens in a new window or tab --> <a href="https://shefali.dev" target="_blank">Open</a> <!-- Opens in the parent frame --> <a href="https://shefali.dev" target="_parent">Open</a> <!-- Opens in the full body of the window --> <a href="https://shefali.dev" target="_top">Open</a> <!-- Opens in the named frame --> <a href="https://shefali.dev" target="framename">Open</a> ``` 提供附加資訊 ------ `title`屬性可用於在使用者將滑鼠懸停在元素上時提供有關該元素的附加資訊。 ``` <p title="World Health Organization">WHO</p> ``` 接受特定文件類型 -------- 可以使用`accept`屬性指定伺服器接受的檔案類型(僅適用於檔案類型)。這與`<input>`元素一起使用。 ``` <input type="file" accept="image/png, image/jpeg" /> ``` 優化影片載入 ------ 您可以透過使用`<video>`元素的`preload`屬性來加快影片檔案的載入速度,從而實現更流暢的播放。 ``` <video src="video.mp4" preload="auto"> Your browser does not support the video tag. </video> ``` 這就是今天的全部內容。 我希望這有幫助。 謝謝閱讀。 欲了解更多此類內容,[請點擊此處](https://shefali.dev/blog)。 您也可以在[X(Twitter)](https://twitter.com/Shefali__J)上關注我,以獲取有關 Web 開發的每日提示。 繼續編碼! [![請我喝杯咖啡](https://cdn.buymeacoffee.com/buttons/default-orange.png)](https://www.buymeacoffee.com/devshefali) --- 原文出處:https://dev.to/devshefali/21-html-tips-you-must-know-about-55j7

我使用 Next.js、GPT4 和 CopilotKit 建立了 v0.dev 克隆

長話短說 ---- 在本文中,您將了解如何建立 Vercel 的 V0.dev 的克隆。這是一個很棒的專案,可以加入到您的投資組合中並磨練您的人工智慧能力。 我們將介紹使用: - 用於應用程式框架的 Next.js 🖥️ - 法學碩士 OpenAI 🧠 - v0 👾 的應用程式邏輯 - 使用 CopilotKit 將 AI 整合到您的應用程式中 🪁 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/shhjdu2k5s02gzoby3p0.gif) --- CopilotKit:應用內人工智慧的作業系統框架 ========================= CopilotKit 是[開源人工智慧副駕駛平台。](https://github.com/CopilotKit/CopilotKit)我們可以輕鬆地將強大的人工智慧整合到您的 React 應用程式中。 建造: - ChatBot:上下文感知的應用內聊天機器人,可以在應用程式內執行操作 💬 - CopilotTextArea:人工智慧驅動的文字字段,具有上下文感知自動完成和插入功能📝 - 聯合代理:應用程式內人工智慧代理,可以與您的應用程式和使用者互動🤖 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8gltoave8490fg234ro.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} (原諒人工智慧的拼字錯誤並給一顆星:) 現在回到文章。 --- 先決條件 ---- 要開始學習本教程,您需要具備以下條件: - 文字編輯器(VS Code、遊標) - React、Next.js、Typescript 和 Tailwind CSS 的基本知識。 - Node.js 安裝在您的 PC/Mac 上 - 套件管理器 (npm) - [OpenAI](https://platform.openai.com/docs/overview) API 金鑰 - [CopilotKit](https://docs.copilotkit.ai/getting-started/quickstart-textarea)安裝在您的 React 專案中 v0是什麼? ------ **v0**是[Vercel 開發的](https://vercel.com/blog/announcing-v0-generative-ui)生成式使用者介面 (UI) 工具,允許使用者給予提示並描述他們的想法,然後將其轉換為用於建立 Web 介面的 UI 程式碼。它利用[生成式 AI](https://medium.com/data-science-at-microsoft/generative-ai-openai-and-chatgpt-what-are-they-3c80397062c4)以及[React](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started) 、 [Tailwind CSS](https://tailwindcss.com/)和[Shadcn UI](https://ui.shadcn.com/)等開源工具,根據使用者提供的描述產生程式碼。 *這是使用 v0 產生的 Web 應用程式 UI 的範例* https://v0.dev/t/nxGnMd1uVGc 了解專案要求 ------ 在本逐步教程結束時,克隆將具有以下專案要求: 1. **使用者輸入:**使用者輸入文字作為提示,描述他們想要產生的 UI。這將使用 CopilotKit 聊天機器人來完成,該聊天機器人由[CopilotSidebar](https://docs.copilotkit.ai/reference/CopilotSidebar)提供。 2. **CopilotKit 整合:** CopilotKit 將用於為 Web 應用程式提供 AI 功能以產生 UI。 3. **渲染 UI:**在 UI React/JSX 程式碼和渲染 UI 之間切換的切換開關。 使用 CopilotKit 建立 v0 克隆 ---------------------- **第 1 步:建立一個新的 Next.JS 應用程式** 在終端機中開啟工作區資料夾並執行以下命令建立新的 Next.js 應用程式: ``` npx create-next-app@latest copilotkit-v0-clone ``` 這將建立一個名為`copilotkit-v0-clone`新目錄,其中包含 Next.JS 專案結構,並安裝了所需的依賴項。它將在您的終端中顯示這一點,並對除最後一個之外的所有選項都選擇**“是”** ,因為建議使用預設`import alias` 。其他提示安裝我們將在專案中使用的 Typescript 和 TailwindCSS。 ![終端](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6l07dxihdi8hw68kv4e.png) 使用`cd`指令導航到專案目錄,如下所示: ``` cd copilotkit-v0-clone ``` **步驟 2:設定 CopilotKit 後端端點。閱讀[文件](https://docs.copilotkit.ai/getting-started/quickstart-backend)以了解更多資訊。** 執行以下命令來安裝 CopilotKit 後端軟體包: ``` npm i @copilotkit/backend ``` 然後造訪 https://platform.openai.com/api-keys 以取得您的**GPT 4** OpenAI API 金鑰。 ![開放伊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ise7y3qnb3cyg4j0mjr6.png) 取得 API 金鑰後,在根目錄中建立一個`.env.local`檔案。 `.env.local`檔案應該是這樣的: ``` OPENAI_API_KEY=Your OpenAI API key ``` 在**app**目錄下建立該目錄; `api/copilot/openai`並建立一個名為`route.ts`的檔案。該檔案用作 CopilotKit 請求和 OpenAI 互動的**後端**端點。它處理傳入的請求,使用 CopilotKit 處理它們,並傳回適當的回應。 我們將在`route.ts`檔案中建立一個POST請求函數,在post請求內部建立一個`CopilotBackend`類別的新實例,該類別提供了處理CopilotKit請求的方法。 然後,我們呼叫`CopilotBackend`實例的`response`方法,並傳遞請求物件 ( `req` ) 和`OpenAIAdapter`類別的新實例作為參數。此方法使用 CopilotKit 和 OpenAI API 處理請求並回傳回應。 如下面的程式碼所示,我們從`@copilotkit/backend`套件導入`CopilotBackend`和`OpenAIAdapter`類別。這些類別對於與 CopilotKit 和 OpenAI API 互動是必需的。 ``` import { CopilotBackend, OpenAIAdapter } from "@copilotkit/backend"; export const runtime = "edge"; export async function POST(req: Request): Promise<Response> { const copilotKit = new CopilotBackend(); return copilotKit.response(req, new OpenAIAdapter()); } ``` **步驟 3:為 v0 克隆建立元件** 我們將使用 Shadcn UI 庫中的元件。要處理這個問題,讓我們透過執行`shadcn-ui init`命令來設定 Shadcn UI 庫來設定您的專案 ``` npx shadcn-ui@latest init ``` 然後我們將用這個問題來配置components.json ``` Which style would you like to use? › Default Which color would you like to use as base color? › Slate Do you want to use CSS variables for colors? › no / yes ``` 我們在 Shadcn UI 中使用的元件是**按鈕**和**對話框**。那麼讓我們來安裝它們吧! 對於[按鈕](https://ui.shadcn.com/docs/components/button),執行此命令 ``` npx shadcn-ui@latest add button ``` 若要安裝[對話](https://ui.shadcn.com/docs/components/dialog)方塊元件,請執行以下命令 ``` npx shadcn-ui@latest add dialog ``` **第 4 步:設定 CopilotKit 前端。閱讀[文件](https://docs.copilotkit.ai/getting-started/quickstart-textarea)以了解更多資訊。** 若要安裝 CopilotKit 前端軟體包,請執行以下命令: ``` npm i @copilotkit/react-core @copilotkit/react-ui ``` 根據[CopilotKit 文件](https://docs.copilotkit.ai/getting-started/quickstart-textarea),要使用 CopilotKit,我們必須設定前端包裝器以透過 Copilot 傳遞任何 React 應用程式。當提示傳遞到 CopilotKit 時,它會透過 URL 將其傳送到 OpenAI,後者會回傳回應。 在**應用程式**目錄中,讓我們更新`layout.tsx`檔案。該文件將定義我們應用程式的佈局結構並將 CopilotKit 整合到前端。 輸入以下程式碼: ``` "use client"; import { CopilotKit } from "@copilotkit/react-core"; import "@copilotkit/react-textarea/styles.css"; // also import this if you want to use the CopilotTextarea component import "@copilotkit/react-ui/styles.css"; import { Inter } from "next/font/google"; import "./globals.css"; import { CopilotSidebar, } from "@copilotkit/react-ui"; const inter = Inter({ subsets: ["latin"] }); export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={inter.className}> <CopilotKit url="/api/copilotkit/openai/"> <CopilotSidebar defaultOpen>{children}</CopilotSidebar> </CopilotKit> </body> </html> ); } ``` 該元件代表我們應用程式的根佈局。它使用 CopilotKit 包裝整個應用程式,根據我們在**步驟 2**中為後端建立的內容指定 CopilotKit 後端端點的 URL ( `/api/copilotkit/openai/` )。此外,它還包括一個 CopilotSidebar 元件,可作為 CopilotKit 的側邊欄,並將 Children 屬性作為其內容傳遞。 **第 5 步:設定主應用程式** 讓我們建立應用程式的結構。它將有一個標題、側邊欄和預覽畫面。 對於**Header** ,導航到**元件**目錄,如下所示, `src/components`然後建立一個`header.tsx`檔案並輸入以下程式碼: ``` import { CodeXmlIcon } from "lucide-react"; import { Button } from "./ui/button"; const Header = (props: { openCode: () => void }) => { return ( <div className="w-full h-20 bg-white flex justify-between items-center px-4"> <h1 className="text-xl font-bold">Copilot Kit</h1> <div className="flex gap-x-2"> <Button className=" px-6 py-1 rounded-md space-x-1" variant={"default"} onClick={props.openCode} > <span>Code</span> <CodeXmlIcon size={20} /> </Button> </div> </div> ); }; export default Header; ``` 對於**側欄,**建立一個`sidebar.tsx`檔案並輸入以下程式碼: ``` import { ReactNode } from "react"; const Sidebar = ({ children }: { children: ReactNode }) => { return ( <div className="w-[12%] min-h-full bg-white rounded-md p-4"> <h1 className="text-sm mb-1">History</h1> {children} </div> ); }; export default Sidebar; ``` 然後對於**預覽**螢幕,建立一個`preview-screen.tsx`檔案並輸入程式碼: ``` const PreviewScreen = ({ html_code }: { html_code: string }) => { return ( <div className="w-full h-full bg-white rounded-lg shadow-lg p-2 border"> <div dangerouslySetInnerHTML={{ __html: html_code }} /> </div> ); }; export default PreviewScreen; ``` 現在讓我們將它們放在一起,打開`page.tsx`檔案並貼上以下程式碼: ``` "use client"; import { useState } from "react"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import Header from "@/components/header"; import Sidebar from "@/components/sidebar"; import PreviewScreen from "@/components/preview-screen"; import { Input } from "@/components/ui/input"; export default function Home() { const [code, setCode] = useState<string[]>([ `<h1 class="text-red-500">Hello World</h1>`, ]); const [codeToDisplay, setCodeToDisplay] = useState<string>(code[0] || ""); const [showDialog, setShowDialog] = useState<boolean>(false); const [codeCommand, setCodeCommand] = useState<string>(""); return ( <> <main className="bg-white min-h-screen px-4"> <Header openCode={() => setShowDialog(true)} /> <div className="w-full h-full min-h-[70vh] flex justify-between gap-x-1 "> <Sidebar> <div className="space-y-2"> {code.map((c, i) => ( <div key={i} className="w-full h-20 p-1 rounded-md bg-white border border-blue-600" onClick={() => setCodeToDisplay(c)} > v{i} </div> ))} </div> </Sidebar> <div className="w-10/12"> <PreviewScreen html_code={readableCode || ""} /> </div> </div> <div className="w-8/12 mx-auto p-1 rounded-full bg-primary flex my-4 outline-0"> <Input type="text" placeholder="Enter your code command" className="w-10/12 p-6 rounded-l-full outline-0 bg-primary text-white" value={codeCommand} onChange={(e) => setCodeCommand(e.target.value)} /> <button className="w-2/12 bg-white text-primary rounded-r-full" onClick={() => generateCode.run(context)} > Generate </button> </div> </main> <Dialog open={showDialog} onOpenChange={setShowDialog}> <DialogContent> <DialogHeader> <DialogTitle>View Code.</DialogTitle> <DialogDescription> You can use the following code to start integrating into your application. </DialogDescription> <div className="p-4 rounded bg-primary text-white my-2"> {readableCode} </div> </DialogHeader> </DialogContent> </Dialog> </> ); } ``` 我們來分解一下上面的程式碼: `const [code, setCode] = useState<string[]>([]);`將用於保存生成的程式碼 `const [codeToDisplay, setCodeToDisplay] = useState<string>(code[0] || "");`將用於保存預覽畫面上顯示的程式碼。 `const [showDialog, setShowDialog] = useState<boolean>(false);`這將保持對話框的狀態,該對話框顯示您可以複製的生成程式碼。 在下面的程式碼中,我們循環產生的程式碼(一串陣列)將其顯示在側邊欄上,這樣當我們選擇一個程式碼時,它就會顯示在預覽畫面上。 ``` <Sidebar> <div className="space-y-2"> {code.map((c, i) => ( <div key={i} className="w-full h-20 p-1 rounded-md bg-white border border-blue-600" onClick={() => setCodeToDisplay(c)} > v{i} </div> ))} </div> </Sidebar> ``` `<PreviewScreen html_code={codeToDisplay} />`在這裡,我們發送要在預覽畫面上顯示的程式碼。預覽畫面元件採用 CopilotKit 產生的程式碼字串,並使用`dangerouslySetInnerHTML`來呈現產生的程式碼。 下面我們有一個`Dialog`元件,它將顯示 CoplilotKit 產生的程式碼,可以將其複製並加入到您的程式碼中。 ``` <Dialog open={showDialog} onOpenChange={setShowDialog}> <DialogContent> <DialogHeader> <DialogTitle>View Code.</DialogTitle> <DialogDescription> You can use the following code to start integrating into your application. </DialogDescription> <div className="p-4 rounded bg-primary text-white my-2"> {readableCode} </div> </DialogHeader> </DialogContent> </Dialog> ``` **步驟6:實作主要應用程式邏輯** 在這一步驟中,我們將 CopilotKit 整合到我們的 v0 克隆應用程式中,以促進人工智慧驅動的 UI 生成。我們將使用 CopilotKit 的 React hook 來管理狀態,使元件可供 Copilot 讀取和操作,並與 OpenAI API 互動。 在您的`page.tsx`檔案中,匯入以下內容: ``` import { CopilotTask, useCopilotContext, useMakeCopilotReadable, } from "@copilotkit/react-core"; ``` 然後我們在`Home`元件中使用`CopilotTask`定義一個`generateCode`任務: ``` const readableCode = useMakeCopilotReadable(codeToDisplay); const generateCode = new CopilotTask({ instructions: codeCommand, actions: [ { name: "generateCode", description: "Create Code Snippet with React.js, tailwindcss.", parameters: [ { name: "code", type: "string", description: "Code to be generated", required: true, }, ], handler: async ({ code }) => { setCode((prev) => [...prev, code]); setCodeToDisplay(code); }, }, ], }); const context = useCopilotContext(); ``` 我們使用`useMakeCopilotReadable`來傳遞現有程式碼並確保可讀性。然後我們使用`CopilotTask`產生UI,並將`generateCode`任務綁定到**生成**按鈕,這樣就可以透過與按鈕元件互動來產生程式碼片段。 此操作由使用者互動觸發,並在呼叫時執行非同步`handler`函數。 `handler`將產生的程式碼新增至程式碼陣列中,更新應用程式狀態以包含新產生的程式碼片段,並將產生的程式碼傳送到預覽畫面上顯示和呈現,預覽畫面也可以複製。 此外, `instructions`屬性指定提供給 Copilot 的命令,該命令儲存在`codeCommand`狀態變數中。 有關`CopilotTask`運作方式的完整說明,請查看此處的文件:https://docs.copilotkit.ai/reference/CopilotTask **第 6 步:執行 v0 克隆應用程式** 至此,我們已經完成了 v0 克隆設置,然後可以透過執行來啟動開發伺服器 ``` npm run dev ``` ![終端](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wm5oddqlzewca34ko0g.png) 可以使用此 URL 在瀏覽器中存取該 Web 應用程式 [http://本地主機:3000](http://localhost:3000/) 然後您可以輸入提示並點擊**“生成”。**這裡有些例子: - **定價頁面:**如下所示,這是產生的UI,有一個切換按鈕可以在UI和React程式碼之間切換: ![在](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cm3gyodvbl0x9i0uvxp9.png) 如果點擊右上角的**Code** &lt;/&gt; 按鈕,它會切換到產生的 UI 的 React 程式碼,如下所示: ![在](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1b5sruonnxl7x42ad8y1.png) - 註冊頁面 UI 範例: ![報名](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/350l7o66l6lq5d4kxiav.png) - 還有一個結帳頁面 ![查看](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dpj6j338fp2gavsvgtti.png) 要克隆專案並在本地執行它,請打開終端並執行以下命令: ``` git clone https://github.com/Tabintel/v0-copilot-next ``` 然後執行`npm install`以安裝專案所需的所有依賴項,並`npm run dev`來執行 Web 應用程式。 結論 -- 總而言之,您可以使用[CopilotKit](https://github.com/CopilotKit/CopilotKit)建立 v0 克隆,為您的設計提供 UI 提示。 CopilotKit 不僅適用於 UI 提示,它還可以用於建立[AI 驅動的 PowerPoint 生成器](https://dev.to/copilotkit/how-to-build-ai-powered-powerpoint-app-nextjs-openai-copilotkit-ji2)、 [AI 簡歷產生器](https://dev.to/copilotkit/how-to-build-the-with-nextjs-openai-1mhb)等應用程式。 可能性是無限的,立即查看 CopilotKit,將您的 AI 想法變為現實。 在[GitHub](https://github.com/Tabintel/v0-copilot-next)上取得完整原始碼。 從[文件](https://docs.copilotkit.ai/getting-started/quickstart-textarea)中了解有關如何使用 CopilotKit 的更多資訊。 另外,別忘了[Star CopilotKit!](https://github.com/CopilotKit/CopilotKit) ⭐ --- 原文出處:https://dev.to/copilotkit/i-created-a-v0-clone-with-nextjs-gpt4-copilotkit-3cmb

50 多個核心 Java 面試問題及程式設計師答案

--- 標題:針對程式設計師的 50 多個核心 Java 面試問題及其答案 發表:真實 描述:核心 Java 面試常見問題及其答案,幫助初學者和初級開發人員獲得第一份 Java 開發工作。 標籤: java、程式設計、職業 封面圖:https://thepracticaldev.s3.amazonaws.com/i/k63545lbbjmh582tiosr.png --- *揭露:這篇文章包含附屬連結;如果您透過本文中提供的不同連結購買產品或服務,我可能會獲得補償。* Java程式設計師大家好!在過去的幾年裡,我一直在分享許多[Java 面試問題](http://javarevisited.blogspot.sg/2015/10/133-java-interview-questions-answers-from-last-5-years.html)、答案和單獨討論。我的許多讀者要求我將他們聚集在一起,以便他們可以在同一個地方進行面試準備。 這篇文章就是這個結果。 本文包含**50 多個 Java 面試問題和答案**,涵蓋所有重要主題,如核心 Java 基礎知識、 [Java 集合框架](https://javarevisited.blogspot.com/2011/11/collection-interview-questions-answers.html)、 [Java 多執行緒和並發](https://javarevisited.blogspot.com/2014/07/top-50-java-multithreading-interview-questions-answers.html)、 [Java IO](https://javarevisited.blogspot.com/2014/08/socket-programming-networking-interview-questions-answers-Java.html) 、 [JDBC](https://javarevisited.blogspot.com/2012/12/top-10-jdbc-interview-questions-answers.html) 、 [JVM 內部原理](http://www.java67.com/2016/08/10-jvm-options-for-java-production-application.html)、 [編碼問題](http://www.java67.com/2018/06/data-structure-and-algorithm-interview-questions-programmers.html)、 [物件導向程式設計](http://www.java67.com/2015/12/top-30-oops-concept-interview-questions-answers-java.html)等。 這些問題是從我做過的各種 Java 訪談中挑選出來的,我的朋友、讀者和其他人根據自己的經驗分享了一些問題。它們絕不是非常困難。您可能已經在電話或面對面的面試中見過它們。 這些問題對於複習重要的 Java 主題(例如核心 Java 概念、多執行緒、lambda、流和集合)也非常有用。 我還分享了一些*用於進一步學習和提高的有用資源*,例如 Udemy 上的[**完整 Java 大師**](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F)課程,您可以加入課程來提高和填補 Java 技能方面的空白。 我還寫過有關 Java 面試準備的書籍,例如[《Grokking the Java Interview》](https://gumroad.com/l/QqjGH)和[《Grokking the Spring Boot Interviews》](https://gumroad.com/l/hrUXKY) ,其中我為 Java 開發人員分享了很多問題。 如果你今年正在準備 Java 面試,你也可以**[在 Gumroad 上取得我的 Java + Spring Interview + SQL Bundle](https://javinpaul.gumroad.com/l/sowpfg)** ,使用程式碼**Friends20**還可獲得 20% 的折扣 [![Java 和 Spring 面試書籍](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xj0hpl0w5lyvdrnwlsoe.png)](https://javinpaul.gumroad.com/l/sowpfg) 那我們還在等什麼?以下是針對初學者和經驗豐富的 Java 開發人員的面試中最常見的一些 Java 問題的清單。 2 至 3 年經驗豐富的程式設計師的 50 個 Java 面試問題 --------------------------------- 因此,為了不浪費您的時間,這裡列出了一些針對初學者程式設計師的常見[核心 Java 面試問題](http://www.java67.com/2018/03/top-50-core-java-interview-questions.html)。此清單主要針對初學者和經驗不足的開發人員,例如具有 2 到 3 年 Java 經驗的人。 1) **Java如何實現平台無關性?** ([回答](http://www.java67.com/2012/08/how-java-achieves-platform-independence.html)) 提示:字節碼和Java虛擬機 答案 - Java 透過產生字節碼然後在 Java 虛擬機器上執行來實現平台獨立性,該虛擬機將這些字節碼轉換為依賴計劃的機器程式碼。由於不同平台的 JVM 不同,我的意思是,對於 Windows,您有單獨的 JRE(其中包括 JVM),對於 Linux,您將有單獨的 JRE。由於 Java 程式碼不會編譯為本機機器碼,而是編譯為字節碼,這使得它們獨立於平台。 2) **Java中的**`**ClassLoader**`**是什麼**? ([回答](http://javarevisited.blogspot.sg/2012/12/how-classloader-works-in-java.html#axzz59AWpr6cb)) 提示:JVM 的一部分,用於載入類別的字節碼。你可以自己寫。 答:在Java中,程式碼被封裝在類別中,因為Java是物件導向的程式設計。你的程式是在類別中寫的,為了執行它們,JVM 會載入這些包含你的程式碼的類別。負責載入類別的 JVM 元件稱為類別載入器。它們是存在的三個主要類別載入器:引導類別載入器、擴充類別載入器和應用程式類別載入器。 這是一個很好的圖表,顯示了每個 Java 類別載入器的功能: [![Java 中的類別載入器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2brxfmzd67dv2k7rwmv.PNG)](https://javarevisited.blogspot.com/2021/05/java-classloader-interview.html) 3)**寫一個Java程式來檢查一個數字是偶數還是奇數?** ([回答](http://javarevisited.blogspot.sg/2013/04/how-to-check-if-number-is-even-or-odd.htm)) 提示:您可以使用位元運算符,例如位元與,記住,二進位格式中偶數末尾為 0,奇數末尾為 1。 4) **Java中**`**ArrayList**`**和**`**HashSet**`**的差別**? ([回答](http://www.java67.com/2012/07/difference-between-arraylist-hashset-in-java.html)) 提示: `List`和`Set`之間的所有差異都適用於此,例如排序、重複、隨機搜尋等。請參閱 Richard Warburton 的[**《Java 基礎知識:集合》**](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections)以了解有關Java 中的ArrayList、HashSet 和其他重要集合的更多資訊。 [![](https://miro.medium.com/max/875/1*hd861fcwDe86tY-1Y0VNRQ.png)](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections) 5)**什麼是單例中的雙重檢查鎖定?** ([回答](http://www.java67.com/2016/04/why-double-checked-locking-was-broken-before-java5.html)) 提示:兩次檢查實例是否已初始化,第一次不加鎖,第二次加鎖。 **6)如何在Java中建立線程安全的Singleton? (** [**回答**](http://javarevisited.blogspot.sg/2012/12/how-to-create-thread-safe-singleton-in-java-example.html)**)** 提示:有很多方法,例如使用 Enum 或使用雙重檢查鎖定模式或使用巢狀靜態類別。 **7) Java中Serialized和Externalized的差別? (** [**回答**](http://www.java67.com/2012/10/difference-between-serializable-vs-externalizable-interface.html)**)** 提示:Externalized 讓您可以更好地控制序列化過程。 **8) Java中何時使用瞬態變數? (**[**回答**](http://www.java67.com/2012/08/what-is-transient-variable-in-java.html)**)** 提示:當您想要在實作 Serialized 介面的類別中使變數不可序列化時。換句話說,您可以將其用於不想保存其值的變數。請參閱[**完整的 Java MasterClass**](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F)以了解 Java 中的瞬態變數。 **9) Java中transient變數和volatile變數的差別? (** [**回答**](http://www.java67.com/2012/11/difference-between-transient-vs-volatile-modifier-variable-java.html)**)** 提示:完全不同,一個用於序列化上下文,另一個用於並發。 **10) Java中什麼時候使用易失性變數? (**[**回答**](http://www.java67.com/2012/08/what-is-volatile-variable-in-java-when.html)**)** 提示:當你需要指示JVM一個變數可以被多個執行緒修改並提示JVM不緩存其值。 **11)我們可以重寫Java中的私有方法嗎? (** [**回答**](http://www.java67.com/2013/08/can-we-override-private-method-in-java-inner-class.html)**)** 提示:不,因為它在子類別中不可見,這是在 Java 中重寫方法的主要要求。 12) **Java中**`**Hashtable**`**和**`**HashMap**`**的差別**? **(** [**回答**](http://javarevisited.blogspot.sg/2010/10/difference-between-hashmap-and.html#axzz53B6SD769)\*\*) \*\*提示:有幾個但最重要的是`Hashtable` ,它是同步的,而`HashMap`不是。與`HashMap`相比,它也是遺留的且緩慢的。 13) **Java中**`**List**`**和**`**Set**`**的差別**? **(** [**回答**](http://javarevisited.blogspot.sg/2012/04/difference-between-list-and-set-in-java.html#axzz53n9YK0Mb)**)** 提示: `List`是有序的並且允許重複。 `Set`是無序的,不允許有重複的元素。 14) **Java中**`**ArrayList**`**和**`**Vector**`**的區別**([**答案**](http://www.java67.com/2012/09/arraylist-vs-vector-in-java-interview.html)**)** 提示:很多,但最重要的是, `ArrayList`是非同步的,速度很快,而`Vector`是同步的,速度很慢。它也是像`Hashtable`這樣的遺留類別。 **15)** **Java 中**`**Hashtable**`**和**`**ConcurrentHashMap**`的差異? **(** [**回答**](http://javarevisited.blogspot.sg/2011/04/difference-between-concurrenthashmap.html#axzz4qw7RoNvw)**)** 提示:更具可擴展性。請參閱 Richard Warburton 的[**《Java 基礎知識:集合》**](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections)以了解更多資訊。 16) `**ConcurrentHashMap**`**如何實現可擴充性? (** [**回答**](http://javarevisited.blogspot.sg/2017/08/top-10-java-concurrenthashmap-interview.html#axzz50U9xyqbo)**)** 提示:透過將映射分為段並僅在寫入操作期間鎖定。 **17) 您將重寫哪兩個方法來將**`**Object**`**用作**`**HashMap**`**中的**`**Key**` **? (** [**回答**](http://www.java67.com/2013/06/how-get-method-of-hashmap-or-hashtable-works-internally.html)**)** 提示:等於和哈希碼 **18) Java中wait和sleep的差別? (**[**回答**](http://www.java67.com/2012/08/what-are-difference-between-wait-and.html)**)** \\ 提示: `wait()`方法釋放鎖定或監視器,而 sleep 則不會。 19\) **Java中**`**notify**`**和**`**notifyAll**`**的差別**? **(** [**回答**](http://www.java67.com/2013/03/difference-between-wait-vs-notify-vs-notifyAll-java-thread.html)**)** 提示: `notify`通知一個隨機執行緒正在等待該鎖,而`notifyAll`通知所有等待監視器的執行緒。如果你確定只有一個執行緒在等待,那麼使用`notify` ,否則`notifyAll`會更好。請參閱 Java Champion Heinz Kabutz 的[**線程基礎迷你課程,**](https://javaspecialists.teachable.com/p/threading-essentials/?product_id=539197&coupon_code=SLACK100?affcode=92815_johrd7r8)以了解有關線程基礎知識的更多資訊。 20\) 為什麼要**在 Java 中重寫 hashcode 以及**`**equals()**` ? **(** [**回答**](http://javarevisited.blogspot.sg/2015/01/why-override-equals-hashcode-or-tostring-java.html#axzz55oDxm8vv)**)** 提示:遵守 equals 和 hashcode 約定,如果您打算將物件儲存到集合類別(例如`HashMap`或`ArrayList`中,則需要遵守這一點。 21) `**HashMap**`**的負載因子是什麼意思? (**[**回答**](http://www.java67.com/2017/08/top-10-java-hashmap-interview-questions.html)**)** 提示:觸發`HashMap`調整大小的閾值一般為 0.75,這表示如果 HashMap 已滿 75%,則`HashMap`會自行調整大小。 **22)** **Java 中**`**ArrayList**`**和**`**LinkedList**`之間的差異? **(** [**回答**](http://www.java67.com/2012/12/difference-between-arraylist-vs-LinkedList-java.html)**)** 提示:與陣列和鍊錶相同,其中一個允許隨機搜尋,而另一種則不允許。在鍊錶上插入和刪除很容易,但在陣列上搜尋很容易。請參閱[**《Java 基礎知識:集合》**](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections) **(** Richard Warburton 在 Pluralsight 上的課程),以了解更多關於 Java 中基本集合資料結構的資訊。 **23)** **Java 中**`**CountDownLatch**`**和**`**CyclicBarrier**`之間的差異? **(** [**回答**](http://www.java67.com/2012/08/difference-between-countdownlatch-and-cyclicbarrier-java.html)**)** 提示:屏障被打破後,您可以重複使用`CyclicBarrier` ,但計數為零後,您無法重複使用`CountDownLatch` 。 24)**在 Java 中什麼時候使用**`**Runnable**`**和**`**Thread**` ? **(** [**回答**](http://www.java67.com/2016/01/7-differences-between-extends-thread-vs-implements-Runnable-java.html)**)** 提示:總是 **25) Java 中 Enum 類型安全的意義是什麼? (** [**回答**](http://www.java67.com/2014/04/what-java-developer-should-know-about-Enumeration-type-in-Java.html)**)** 提示:這表示您不能將不同 Enum 類型的實例指派給 Enum 變數。例如,如果您有一個像`DayOfWeek` day 這樣的變數,那麼您無法從`DayOfMonth`枚舉中為其指派值。 **26) Java 中整數的自動裝箱如何運作? (** [**回答**](http://javarevisited.blogspot.sg/2012/07/auto-boxing-and-unboxing-in-java-be.html#axzz59AWpr6cb)**)** 提示:透過使用Java中的`valueOf()`方法。 **27)** **Java 中**`**PATH**`**和**`**Classpath**`之間的差異? **(** [**回答**](http://www.java67.com/2012/08/what-is-path-and-classpath-in-java-difference.html)**)** 提示:作業系統使用`PATH` ,而JVM 使用`Classpath`來定位Java 二進位文件,例如JAR 檔案或Class 檔案。請參閱[**Java 基礎知識:核心平台**](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-core-platform),以了解有關`PATH` 、 `Classpath`和其他 Java 環境變數的更多資訊。 [![](https://miro.medium.com/max/478/1*PBuMgGmVXwBguv-SPw7YJw.jpeg)](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-core-platform) **28) Java中方法重載和重寫的差別? (** [**回答**](http://www.java67.com/2015/08/top-10-method-overloading-overriding-interview-questions-answers-java.html)**)** 提示:重寫發生在子類別中,而重載發生在同一個類別中。此外,覆蓋是執行時活動,而重載是在編譯時解決的。 **29) 如何防止 Java 中的類別被子類化? (**[**回答**](http://www.java67.com/2017/06/10-points-about-final-modifier-in-java.html)**)** \\ 提示:只需將其建構函數設為私有即可 **30) 你如何限制你的類別被你的客戶使用? (** [**回答**](http://javarevisited.blogspot.sg/2016/01/why-jpa-entity-or-hibernate-persistence-should-not-be-final-in-java.html)**)** \\ 提示:使建構子私有或從建構子拋出異常 **31)** **Java 中**`**StringBuilder**`**和**`**StringBuffer**`之間的差異? **(**[**回答**](http://www.java67.com/2016/10/5-difference-between-stringbuffer.html)**)** 提示: `StringBuilder`不同步,而`StringBuffer`同步。 **32) Java 中多態性與繼承的差別? (** [**回答**](http://www.java67.com/2014/04/difference-between-polymorphism-and-Inheritance-java-oops.html)**)** 提示:繼承允許程式碼重複使用並建構類別之間的關係,這是多態性所需要的,多態性提供動態行為。請參閱\[**物件導向的 Java 程式設計:資料結構及超越專業化**\]( https://coursera.pxf.io/c/3294490/1164545/14726?u=https%3A%2F%2Fwww.coursera.org%2Fspecializations%2Fjava-object-orientation)在Coursera 上,了解有關OOP 功能的更多資訊。適合初學者的最深入的課程之一。 \[![](https://thepracticaldev.s3.amazonaws.com/i/vuohxotp8qeh638lzjpr.png) \]( https://coursera.pxf.io/c/3294490/1164545/14726?u=https%3A%2F%2Fwww.coursera.org%2Fspecializations%2Fjava-物件導向) 順便說一句,如果您發現 Coursera 課程很有用,因為它們是由世界各地的知名公司和大學建立的,我建議您加入[**Coursera Plus**](https://coursera.pxf.io/c/3294490/1164545/14726?u=https%3A%2F%2Fwww.coursera.org%2Fcourseraplus) ,這是Coursera 的訂閱計劃,可以讓您無限制地存取他們最受歡迎的課程、專業、專業憑證和指導專案。它的費用約為 399 美元/年,但它完全物有所值,因為您可以獲得無限的憑證。 **33)我們可以在Java中重寫靜態方法嗎? (**[**回答**](http://www.java67.com/2012/08/can-we-override-static-method-in-java.html)**)** \\ 提示:否,因為重寫在執行時間解析,而靜態方法呼叫在編譯時解析。 **34) 我們可以存取Java中的私有方法嗎? (**[**回答**](http://www.java67.com/2012/08/can-we-override-private-method-in-java.html)**)** \\ 提示:可以,在同一個班級內,但不能在班級外 **35) Java中介面和抽象類別的區別? (** [**回答**](http://www.java67.com/2017/08/difference-between-abstract-class-and-interface-in-java8.html)**)** 提示:從[Java 8](https://dzone.com/articles/5-courses-to-crack-java-certification-ocajp-1z0-80)開始,差異變得模糊。然而,一個Java類別仍然可以實作多個接口,但只能擴展一個類別。 **36) Java 中 DOM 和 SAX 解析器的差別? (**[**回答**](http://www.java67.com/2012/09/dom-vs-sax-parser-in-java-xml-parsing.html)**)** \\ 提示:DOM 將整個 XML 檔案載入到記憶體中,而 SAX 則不會。它是一個基於事件的解析器,可用於解析大文件,但 DOM 速度很快,對於小文件應該是首選。 **37) Java 中 throw 和 throws 關鍵字的差異? (**[**回答**](http://www.java67.com/2012/10/difference-between-throw-vs-throws-in.html)**)** \\ 提示: throws 聲明方法在發生錯誤時可以拋出什麼異常,但 throw 關鍵字實際上會拋出異常。請參閱[**Java 基礎知識:異常處理**](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-exception-handling)以了解有關 Java 中異常處理的更多資訊。 [![](https://miro.medium.com/max/875/1*O5DEoN9mOy3D0HxFKWwfKQ.png)](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-exception-handling) **38) Java 中的故障安全迭代器和故障快速迭代器的差異? (** [**回答**](http://www.java67.com/2015/06/what-is-fail-safe-and-fail-fast-iterator-in-java.html)**)** 提示:故障安全性不會拋出`ConcurrentModificationException` ,而`fail-fast`則在迭代時檢測到底層集合的外部變更時拋出 ConcurrentModificationException。 **39) Java 中迭代器和枚舉的差別? (** [**回答**](http://javarevisited.blogspot.sg/2010/10/what-is-difference-between-enumeration.html#axzz59AWpr6cb)**)** 提示:迭代器還使您能夠在迭代時刪除元素,而枚舉不允許這樣做。 **40)** **Java 中的**`**IdentityHashMap**`是什麼? **(** [**回答**](http://www.java67.com/2016/09/difference-between-identityhashmap-weakhashmap-enummap-in-java.html)**)** 提示:一個`Map` ,它使用`==`相等運算子來檢查相等性,而不是`equals()`方法。 **41)** **Java 中的**`**String**`池是什麼? **(** [**回答**](http://javarevisited.blogspot.sg/2016/07/difference-in-string-pool-between-java6-java7.html#axzz4pGGwsyna)**)** 提示: `String`文字池。請記住,它已從 JDK 7 中的永久代空間移至堆疊。 **42)** Java 中`**Serializable**`**類別可以包含不可序列化欄位嗎? (** [**回答**](http://javarevisited.blogspot.sg/2016/09/how-to-serialize-object-in-java-serialization-example.html)\*\*) \*\*提示:是的,但您需要將其設定為靜態或瞬態。 **43) Java 中 this 和 super 的差別? (**[**回答**](http://www.java67.com/2013/06/difference-between-this-and-super-keyword-java.html)**)** 提示:this 指的是目前實例,而 super 指的是超類別的實例。 **44)** **Java 中**`**Comparator**`**和**`**Comparable**`之間的差異? **(** [**回答**](http://www.java67.com/2013/08/difference-between-comparator-and-comparable-in-java-interface-sorting.html)**)** \\ 提示: `Comparator`定義自訂排序,而`Comparable`定義物件的自然順序,例如`String`字母順序。請參閱[**完整的 Java 大師課程**](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F)以了解有關 Java 排序的更多資訊。 [![](https://miro.medium.com/max/875/1*MTR8OytpiIMidLndBnsJ5g.png)](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F) **45)** **Java 中**`**java.util.Date**`**和**`**java.sql.Date**`之間的差異? **(**[**回答**](http://javarevisited.blogspot.sg/2012/04/difference-between-javautildate-and.html)**)** 提示:前者包含日期和時間,後者僅包含日期部分。 46)為什麼**Java中的**`**Object**`類別**中宣告了wait和notify方法**? **(**[**回答**](http://javarevisited.blogspot.sg/2012/02/why-wait-notify-and-notifyall-is.html)**)** 提示:因為它們需要僅對物件可用的鎖。 **47)為什麼Java不支援多重繼承? (** [**回答**](http://javarevisited.blogspot.sg/2011/07/why-multiple-inheritances-are-not.html)**)** 提示:它不支持,因為 C++ 的體驗不好,但對於 Java 8,它在某種意義上是支援的 --- 現在 Java 中不支援`Type`的多重繼承。 **48) Java 中檢查異常和非檢查異常的差異? (** [**回答**](http://javarevisited.blogspot.sg/2011/12/checked-vs-unchecked-exception-in-java.html)**)** 提示:如果是選取的,則必須使用 catch 區塊處理異常,而如果是未選取的,則由您決定;編譯不會打擾你。 **49) Java 中錯誤和異常的區別? (**[**回答**](http://www.java67.com/2012/12/difference-between-error-vs-exception.html)**)** 提示:我厭倦了打字,請檢查答案 **50) Java 中的競爭條件和死鎖的差異? (** [**回答**](http://javarevisited.blogspot.sg/2012/02/what-is-race-condition-in.html#axzz59AbkWuk9)**)** 提示:這兩種錯誤都是並發應用程式中發生的錯誤,一種是由於執行緒調度而發生的,另一種是由於編碼不良而發生的。請參閱[Java 中的多執行緒和平行計算](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fmultithreading-and-parallel-computing-in-java%2F),以了解有關死鎖、競爭條件和其他多執行緒問題的更多資訊。 其他資源 --- - [Java 面試指南:200+ 面試題目及答案](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-interview-questions-and-answers%2F) - [Spring框架面談指南---200+問答](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fspring-interview-questions-and-answers%2F) - [準備工作面試 作者:John Sonmez](https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fdeveloper-job-interviews) - [Markham 曝光的 Java 程式設計面試](http://www.amazon.com/Java-Programming-Interviews-Exposed-Markham/dp/1118722868?tag=javamysqlanta-20) - [破解編碼面試 --- 189 個問題和答案](http://www.amazon.com/Cracking-Coding-Interview-6th-Edition/dp/0984782850/?tag=javamysqlanta-20) - [求職面試的資料結構與演算法分析](https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fdata-structure-and-algorithms-analysis%2F) - [過去 5 年 130 多道 Java 面試題](http://javarevisited.blogspot.sg/2015/10/133-java-interview-questions-answers-from-last-5-years.html) - [Grokking the Java Interview - 免費範例 PDF](https://javinpaul.gumroad.com/l/HMOAv) - [深入了解 Spring Boot 面試 - 免費 PDF 範本](https://javinpaul.gumroad.com/l/grokking-springboot-interview-sample) ### 結束語 謝謝,您已經讀到了文章的結尾...祝您程式設計面試順利!這當然不會很容易,但這些問題肯定會對您有所幫助。它還會鼓勵您了解更多。 如果您喜歡這篇文章,請與您的朋友和同事分享,並且不要忘記在 Twitter 上關注[javinpaul](https://twitter.com/javinpaul) ! > **PS ---**如果您需要一些免費資源來學習 Java,您可以查看[**我最喜歡的免費 Java 課程**](https://medium.com/javarevisited/10-free-courses-to-learn-java-in-2019-22d1f33a3915)清單來開始您的準備。 &gt; > **PSS ---**我沒有提供圖片中分享的面試問題的答案“程式碼中建立了多少個 String 物件?”你能猜出並解釋一下嗎? 而且,如果你今年正在準備 Java 面試,你還可以**[在 Gumroad 上取得我的 Java + Spring Interview + SQL Bundle](https://javinpaul.gumroad.com/l/sowpfg)** ,使用程式碼**friends20**也可以獲得 20% 的折扣 --- 原文出處:https://dev.to/javinpaul/50-core-java-interview-questions-with-answers-for-programmers-3bc

從頭開始寫簡單的程式語言 - 第 1 部分

如果您是開發人員,您就使用過程式語言。它們是讓電腦做你想做的事的好方法。也許您甚至已經深入研究過彙編或機器碼程式設計。許多人再也不想回來。但有些人想知道,我怎麼能透過做更多的低階程式來更折磨自己呢?我想更多地了解程式語言是如何製作的!開個玩笑,寫一門新語言並不像聽起來那麼糟糕,所以如果你有一點好奇心,我建議你留下來看看它是關於什麼的。 這篇文章的目的是簡單地介紹如何建立程式語言,以及如何建立自己的特殊語言。甚至可以用自己的名字命名。誰知道。 我還敢打賭,這似乎是一項令人難以置信的艱鉅任務。別擔心,因為我已經考慮過這一點。我盡力相對簡單地解釋了一切,沒有講*太多*離題的話。在這篇文章結束時,您將能夠建立自己的程式語言(將有幾個部分),但還有更多。了解幕後發生的事情會讓你更好地進行除錯。您將更能理解新的程式語言以及為何它們做出這樣的決定。如果我之前沒有提到的話,你可以擁有一種以你自己的名字命名的程式語言。而且,這真的很有趣。至少對我來說。 編譯器和解釋器 ------- 程式語言通常是高階的。也就是說,你看的不是0和1,也不是暫存器和組合程式碼。但是,您的電腦只能辨識 0 和 1,因此它需要一種方法來從您輕鬆讀取的內容轉變為機器可以輕鬆讀取的內容。該翻譯可以透過編譯或解釋來完成。 編譯是將原始語言的整個原始檔轉換為目標語言的過程。出於我們的目的,我們將考慮從全新的、最先進的語言一直編譯到可執行的機器碼。 ![簡單編譯圖](https://thepracticaldev.s3.amazonaws.com/i/c5difsv2s2rvk1iwzcih.png) 我的目標是讓「魔法」消失 解釋是或多或少直接執行原始檔中的程式碼的過程。我會讓你覺得這很神奇。 那麼,如何從易於閱讀的原始語言變成難以理解的目標語言呢? 編譯器的階段 ------ 編譯器可以透過多種方式分為多個階段,但有一種方法是最常見的。當你第一次看到它時,它的意義不大,但它是這樣的: ![編譯器的虛假階段](https://thepracticaldev.s3.amazonaws.com/i/cq1uo0x1gp7k73jldp7o.png) 哎呀,我選錯了圖,但這樣就可以了。基本上,您獲取原始文件,將其設置為計算機想要的格式(刪除空格之類的內容),將其更改為計算機可以很好地移動的格式,然後從中生成程式碼。還有更多。那是下次,或者如果你的好奇心快要殺死你的話,也可以供你自己研究。 詞法分析 ---- ### 又名“讓原始碼變得漂亮” 考慮以下完全虛構的語言,它基本上只是一個帶有分號的計算器: ``` // source.ect 3 + 3.2; 5.0 / 1.9; 6 * 2; ``` 計算機不需要所有這些。空間只適合我們狹隘的頭腦。還有新線?沒有人需要那些。電腦將您看到的程式碼轉換為可以使用的標記流,而不是原始檔案。基本上,它知道`3`是整數, `3.2`是浮點數, `+`是對這兩個值進行運算的東西。這就是計算機*真正*需要完成的全部工作。**詞法分析器**的工作是提供這些標記而不是原始程式。 它的實現方式非常簡單:給詞法分析器(詞法分析器的一種聽起來不那麼自命不凡的說法)一些期望的東西,然後告訴它當它看到這些東西時要做什麼。這些稱為*規則*。這是一個例子: ``` int cout << "I see an integer!" << endl; ``` 當 int 通過詞法分析器並執行此規則時,您將看到一個非常明顯的“我看到一個整數!”感嘆。這不是我們使用詞法分析器的方式,但看到程式碼執行是任意的很有用:沒有規則要求您必須建立某個物件並傳回它,它只是常規的舊程式碼。甚至可以用大括號括起來來使用多條線。 順便說一句,我們將使用稱為[FLEX 的](https://github.com/westes/flex)東西來進行詞法分析。它使事情變得非常簡單,但是沒有什麼可以阻止您自己編寫一個程式來執行此操作。 為了了解我們如何使用 flex,請看這個例子: ``` // scanner.lex /* Definitions */ %{ #include <iostream> using namespace std; extern "C" int yylex(); %} /* Rules next */ %% [0-9]+.[0-9]+ cout << "FLOAT: (" << yytext << ")" << endl; [0-9]+ cout << "INT: (" << yytext << ")" << endl; "+" cout << "PLUS" << endl; "-" cout << "MINUS" << endl; "*" cout << "TIMES" << endl; "/" cout << "DIVIDED BY" << endl; ";" cout << "SEMICOLON" << endl; [\t\r\n\f] ; /* ignore whitespace */ %% /* Code */ int main() { yylex(); } ``` 這引入了一些新概念,讓我們回顧一下它們: `%%`用於分隔 .lex 檔案的各個部分。第一部分是聲明 - 基本上是使詞法分析器更具可讀性的變數。這也是您導入的位置,由`%{`和`%}`包圍。 第二部分是規則,我們之前已經看過。這些基本上是一個大的`if` `else if`塊。它將執行*最長的匹配*行。因此,即使您更改 float 和 int 的順序,float 仍然會匹配,因為匹配`3.2`的 3 個字元比`3`的 1 個字元多。請注意,如果這些規則均不匹配,則會採用預設規則,只需將字元列印到標準輸出即可。然後,您可以使用`yytext`來引用它看到的與該規則相符的內容。 第三部分是程式碼,它只是在執行時執行的 C 或 C++ 原始碼。 `yylex();`是執行詞法分析器的函數呼叫。您也可以讓它從檔案中讀取輸入,但預設情況下它從標準輸入中讀取。 假設您將這兩個檔案建立為`source.ect`和`scanner.lex` 。我們可以使用`flex`命令建立一個 C++ 程式(假設您已經安裝了`flex` ),然後編譯它並輸入我們的原始程式碼以達到我們很棒的列印語句。讓我們將其付諸行動吧! ``` evan:ectlang/ $ flex scanner.lex evan:ectlang/ $ g++ lex.yy.c -lfl evan:ectlang/ $ ./a.out < source.ect INT: (3) PLUS FLOAT: (3.2) SEMICOLON FLOAT: (5.0) DIVIDED BY FLOAT: (1.9) SEMICOLON INT: (6) TIMES INT: (2) SEMICOLON evan:ectlang/ $ ``` 嘿,酷!您只需編寫將輸入與規則相符的 C++ 程式碼,以便執行某些操作。 現在,編譯器如何使用它?一般來說,每個規則都會返回一些東西,而不是打印一些東西——一個令牌!這些標記可以在編譯器的下一部分中定義... 語法分析器 ----- ### 又名“使漂亮的源程式碼可用” 是時候玩得開心了!一旦我們到達這裡,我們就開始定義程式的結構。解析器只是獲得一個標記流,它必須匹配該流中的元素,以使原始程式碼具有可用的結構。為了做到這一點,它使用了[語法](https://en.wikipedia.org/wiki/Formal_grammar),你可能在理論課上看到或聽到你奇怪的朋友閒聊的東西。它們非常強大,並且有很多東西需要了解,但我只會提供您需要了解的關於我們有點愚蠢的解析器的資訊。 基本上,語法將非終結符與終結符和非終結符的某種組合相匹配。終端是樹的葉子;非終端有孩子。如果這沒有意義,請不要擔心,程式碼可能會更容易理解。 我們將使用一個名為[Bison 的](https://www.gnu.org/software/bison/)解析器產生器。這次,為了解釋目的,我將把文件分成幾個部分。首先,聲明: ``` // parser.y %{ #include <iostream> using namespace std; extern "C" void yyerror(char *s); extern "C" int yyparse(); %} %union{ int intVal; float floatVal; } %start program %token <intVal> INTEGER_LITERAL %token <floatVal> FLOAT_LITERAL %token SEMI %type <floatVal> exp %type <floatVal> statement %left PLUS MINUS %left MULT DIV ``` 第一部分應該看起來很熟悉:我們正在導入我們想要使用的東西。之後就變得有點棘手了。 聯合是「真正的」C++ 類型到我們將在整個程式中呼叫它的類型的映射。因此,當我們看到`intVal`時,您可以將頭腦中的值替換為`int` ,而當我們看到`floatVal`時,您可以將頭腦中的值替換為`float` 。稍後你就會明白為什麼。 接下來我們來看看符號。您可以在腦海中將它們分為終結符和非終結符,就像我們之前討論的語法一樣。大寫字母表示終端,因此它們不會繼續擴展。小寫意味著非終結符,因此它們繼續擴展。這只是慣例。 每個聲明(以`%`開頭)聲明一些符號。首先,我們看到我們從一個非終端`program`開始。然後,我們定義一些標記。 `<>`括號定義回傳類型:因此`INTEGER_LITERAL`終端機回傳`intVal` 。 `SEMI`終端不會回傳任何內容。使用`type`可以對非終結符完成類似的操作,如將`exp`定義為傳回`floatVal`的非終結符時所見。 最後我們取得了優先權。我們知道 PEMDAS,或者您可能已經學過的任何其他縮寫詞,它告訴您一些簡單的優先規則:乘法在加法之前,等等。現在,我們以一種奇怪的方式在這裡聲明這一點。首先,清單中的位置越低意味著優先順序越高。其次,您可能想知道`left`是什麼意思。這就是關聯性:差不多,如果我們有`a op b op c` , `a`和`b`會在一起,還是`b`和`c`會在一起?我們的大多數運算子都執行前者,即`a`和`b`首先結合在一起:這稱為左結合性。某些運算子(例如求冪)會執行相反的操作: `a^b^c`期望您先提高`b^c`然後再提高`a^(b^c)` 。不過,我們不會處理這個問題。如果您想了解更多詳細訊息,請查看 Bison 頁面。 好吧,我可能已經厭倦了聲明,這是語法規則: ``` // parser.y %% program: /* empty */ | program statement { cout << "Result: " << $2 << endl; } ; statement: exp SEMI exp: INTEGER_LITERAL { $$ = $1; } | FLOAT_LITERAL { $$ = $1; } | exp PLUS exp { $$ = $1 + $3; } | exp MINUS exp { $$ = $1 - $3; } | exp MULT exp { $$ = $1 * $3; } | exp DIV exp { $$ = $1 / $3; } ; ``` 這就是我們之前講的文法。如果您不熟悉語法,這非常簡單:左側可以變成右側的任何內容,並用`|`分隔。 (邏輯`or` )。如果它可以走多條路徑,那就是不行的,我們稱之為*歧義語法*。由於我們的優先聲明,這並不含糊 - 如果我們更改它,使 plus 不再保持關聯,而是聲明為像`SEMI`這樣的`token` ,我們會看到發生移位/歸約衝突。想知道更多?看看Bison是如何運作的,提示,它使用LR解析演算法。 好的,所以`exp`可以是以下情況之一: `INTEGER_LITERAL` 、 `FLOAT_LITERAL`等。請注意,它也是遞歸的,因此`exp`可以變成兩個`exp` 。這允許我們使用複雜的表達式,例如`1 + 2 / 3 * 5` 。請記住,每個`exp`都會傳回一個 float 類型。 括號內的內容與我們在詞法分析器中看到的相同:任意 C++ 程式碼,但帶有更奇怪的語法糖。在這種情況下,我們有一些以`$`開頭的特殊變數。變數`$$`基本上就是回傳的內容。 `$1`是第一個參數傳回的內容, `$2`第二個參數傳回的內容,等等。我所說的「參數」是指語法規則的一部分:因此規則`exp PLUS exp`有參數 1 `exp` 、參數 2 `PLUS`和參數 3 `exp` 。因此,在程式碼執行中,我們將第一個表達式的結果加到第三個表達式中。 最後,一旦它回到`program`非終端,它將列印語句的結果。在這種情況下,程式是一堆語句,其中語句是一個表達式,後面跟著一個分號。 現在我們來編寫程式碼部分。這是當我們通過解析器時實際執行的內容: ``` // parser.y %% int main(int argc, char **argv) { if (argc < 2) { cout << "Provide a filename to parse!" << endl; exit(1); } FILE *sourceFile = fopen(argv[1], "r"); if (!sourceFile) { cout << "Could not open source file " << argv[1] << endl; exit(1); } // Sets input for flex to the file instead of standard in yyin = sourceFile; // Now let's parse it! yyparse(); } // Called on error with message s void yyerror(char *s) { cerr << s << endl; } ``` 好吧,這開始變得有趣了。我們的主函數現在從第一個參數提供的檔案而不是標準輸入中讀取,並且我們加入了一些錯誤程式碼。這是非常不言自明的,並且註釋很好地解釋了正在發生的事情,所以我將把它作為練習留給讀者來弄清楚這一點。您需要知道的是現在我們回到詞法分析器以向解析器提供標記!這是我們的新詞法分析器: ``` // scanner.lex %{ extern "C" int yylex(); #include "parser.tab.c" // Defines the tokens %} %% [0-9]+ { yylval.intVal = atoi(yytext); return INTEGER_LITERAL; } [0-9]+.[0-9]+ { yylval.floatVal = atof(yytext); return FLOAT_LITERAL; } "+" { return PLUS; } "-" { return MINUS; } "*" { return MULT; } "/" { return DIV; } ";" { return SEMI; } [ \t\r\n\f] ; /* ignore whitespace */ ``` 嘿嘿,現在確實變小了!我們看到的是,我們回傳的是終端符號,而不是列印。其中一些,例如整數和浮點數,我們首先在繼續之前設定值( `yylval`是終端符號的回傳值)。除此之外,它只是為解析器提供了一個終端標記流以供其自行決定使用。 酷,那麼讓我們執行吧! ``` evan:ectlang/ $ bison parser.y evan:ectlang/ $ flex scanner.lex evan:ectlang/ $ g++ lex.yy.c -lfl evan:ectlang/ $ ./a.out source.ect Result: 6.2 Result: 2.63158 Result: 12 ``` 我們開始了 - 我們的解析器列印出正確的值!但這並不是真正的編譯器,它只是執行 C++ 程式碼來執行我們想要的內容。為了製作編譯器,我們希望將其轉換為機器碼。為此,我們需要加入一點... 直到下次... ------- 我現在意識到這篇文章會比我想像的要長很多,所以我想我應該在這裡結束這篇文章。我們基本上有一個可用的詞法分析器和解析器,所以這是一個很好的停止點。 如果您對最終產品感到好奇,我已將原始程式碼放在[我的 Github](https://github.com/evantypanski/ectlang)上。隨著更多帖子的發布,該存儲庫將出現更多活動。 有了我們的詞法分析器和解析器,我們現在可以產生程式碼的中間表示,該中間表示最終可以轉換為真實的機器碼,我將向您展示具體的操作方法。 [第 2 部分來了!](https://dev.to/evantypanski/writing-a-simple-programming-language-from-scratch-part-2-2522) ### 其他資源 如果您想了解有關此處介紹的任何內容的更多訊息,我已經連結了一些內容以供您開始使用。我已經講了很多,所以這是我向您展示如何深入研究這些主題的機會。 - Flex 程式碼庫: <https://github.com/westes/flex> - 我們使用的詞法分析工具。 - Bison 文件: <https://www.gnu.org/software/bison/> - 我們使用的解析器產生器。這裡有很棒的文件。 - LALR 解析: <https://web.cs.dal.ca/~sjackson/lalr1.html> - 關於 LALR(1) 解析器(如 Bison 產生的解析器!)如何運作的精心解釋。 - 解決解析衝突: <http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/conflict.html> - 如何解決shift/reduce或reduce/reduce衝突,就像我們之前看到的那樣。 - Chomsky 層次結構: [https://en.wikipedia.org/wiki/Chomsky\_hierarchy](https://en.wikipedia.org/wiki/Chomsky_hierarchy) - 對此沒有詳細介紹,但我們使用了上下文無關語法,以便 Bison 可以編譯它。如果您需要上下文敏感性,那是為了後面的階段。 - 符號表: [https://www.tutorialspoint.com/compiler\_design/compiler\_design\_symbol\_table.htm](https://www.tutorialspoint.com/compiler_design/compiler_design_symbol_table.htm) - 使用符號表,編譯器如何處理變數。 哦,順便說一句,如果您不喜歡我的編譯器階段,這裡有一個實際的圖表。我仍然保留了符號表和錯誤處理程序。另請注意,許多圖表與此不同,但這最好地說明了我們所關心的內容。 ![編譯器的實際階段](https://thepracticaldev.s3.amazonaws.com/i/4bgv9blwleizrmcfw2fq.png) --- 原文出處:https://dev.to/evantypanski/writing-a-simple-programming-language-from-scratch-part-1-54a2

令人難以置信的 JavaScript 動畫庫

概述 -- JavaScript 動畫庫已成為開發人員的必備工具,旨在透過迷人的互動式視覺元素來豐富 Web 應用程式。這些庫的發展極大地簡化了動畫過程,使其更易於存取。透過利用適當的函式庫,開發人員能夠製作令人印象深刻的動畫,從而增強網站和應用程式的參與度和使用者體驗。 動畫有可能大幅改變網站的美感和氛圍。當明智地利用它們來增強用戶體驗時,它們就會成為寶貴的資產。動畫在吸引註意力和增加網站停留時間方面特別有效,從而增加流量。 GSAP ------ ![總體規劃計劃](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p88xykg0uhg90oj4xckg.png) [GSAP(GreenSock 動畫平台)](https://greensock.com/gsap/)作為領先且強大的 JavaScript 動畫庫脫穎而出,專為速度和效率而設計。它擁有一系列功能,包括基於時間軸的動畫、SVG 支援和緩動功能。 GSAP 提供了各種預先設計的工具和功能,即使是網頁動畫新手也能快速有效地建立複雜的動畫。 GSAP 有助於跨 jQuery、Canvas 和 SVG 建立精美的高效能動畫。它與其他軟體和函式庫相容,例如[PixiPlugin](https://greensock.com/docs/v2/Plugins/PixiPlugin) 、 [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) 、 [EaseJS](https://createjs.com/easeljs)等。 ### 好處 - 輕便快捷 - 廣泛的功能 - 可透過插件擴展 - 適應各種螢幕尺寸 - 支援所有主流瀏覽器 Anime.js ----- ![動漫.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9suyvmlz3kzt9tooinls.png) [Anime.js](https://animejs.com/)以其簡單、速度和多功能性而聞名。這個緊湊的庫簡化了動畫過程,使開發人員能夠以最少的努力製作出視覺上引人注目的動畫。 Anime.js 支援多種效果,例如縮放、變形和旋轉,為開發人員提供了輕鬆建立複雜時間軸和動畫的工具。 ### 好處 - 直覺的API - 結構緊湊、適應性強 - 豐富的功能集 - 插件就緒架構 - 支援所有主流瀏覽器 Three.js ---- ![三.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqy0o2cm5obswsc9kp3y.png) [Three.js](https://threejs.org/)致力於產生 3D 視覺效果,提供一套強大的功能和工具。它建立在[WebGL](https://get.webgl.org/)之上,優化 GPU 使用以實現快速渲染,確保跨裝置(包括資源有限的裝置)的流暢效能。 Three.js 的多功能性允許建立廣泛的 3D 圖形和動畫,從簡單的形狀到複雜的模型。 Popmotion.io ------------ ![popmotion.io](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9u79jz8iilrbp65zx4h5.png) [Popmotion](https://popmotion.io/)在設計中優先考慮簡單性和易用性。它用[TypeScript](https://www.typescriptlang.org/)編寫,與任何接受數位輸入的 API 相容,提供簡單的 API 並支援主要瀏覽器。 Popmotion 的架構為[Framer Motion](https://www.framer.com/motion/)中的動畫提供支持,並且可以透過外掛程式進行擴充。 ### 好處 - 使用者友善的介面 - 可擴充的插件框架 - 響應式設計 - 支援所有主流瀏覽器 反應彈簧 ---- ![反應彈簧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ny6fonq8dw3udlcejqfn.png) [React-spring](https://www.react-spring.dev/)專為 React 應用程式量身定制,透過其簡單的 API 提供跨所有主要瀏覽器的無縫動畫體驗。它不僅迎合 Web 環境,還支援 React-Native、React-Three-Fiber、React-Konva 和 React-ZDog。它的 TypeScript 基礎有助於輕鬆整合到現有專案中。 ### 好處 - 簡單易懂 - 啟用插件以增加功能 - 跨裝置回應 - 支援所有主流瀏覽器 Vivus - ![活](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4zdqw3xeq1vxrrlgx1u.png) [Vivus](https://maxwellito.github.io/vivus/)專注於 SVG 動畫,具有易於使用的 API,確保跨所有主要瀏覽器的兼容性。它支援各種動畫樣式,例如延遲、同步或 OneByOne,並允許為每個 SVG 路徑自訂動畫腳本。 ### 好處 - 毫不費力地實施 - 插件擴充性 - 專用的 SVG 動畫功能 - 支援所有主流瀏覽器 Mo.js ----- ![Mo.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3rhzp2ggqfy8t61fvkd.png) [Mo.js](https://mojs.github.io/)是一個強大且適應性強的 JavaScript 動畫庫,具有簡單的 API 和瀏覽器支援。它以其高性能動畫和與密度無關的效果而著稱,確保在任何設備上都有出色的視覺品質。 Mo.js 提供了廣泛的動畫建立工具,包括用於動畫控制的播放器、曲線編輯器和用於自訂緩動和編輯的時間軸編輯器。 ### 好處 - 強大而靈活 - 直覺的API - 插件相容 - 專為響應式環境設計 - 支援所有主流瀏覽器 結論 -- 為您的專案選擇正確的動畫庫可能是一項艱鉅的任務。還有許多其他 JavaScript 動畫庫可用,每個庫都具有獨特的特性和功能。 您是否有此處未提及的最喜歡的圖書館?請在下面的評論中分享。我總是渴望探索新工具並擴展我的工具包! 如果您發現這有幫助並願意給我的專案一顆星以支持,我將不勝感激! [黏土主題🚀](https://github.com/lilxyzz/clay-theme) --- 原文出處:https://dev.to/lilxyzz/incredible-javascript-animation-libraries-30on

React 元件設計模式 - 第 1 部分

React 設計模式是開發人員用來解決使用 React 建立應用程式時遇到的常見問題和挑戰的既定實踐和解決方案。這些模式封裝了針對重複出現的設計問題的可重複使用解決方案,從而提高了可維護性、可擴展性和效率。它們提供了一種結構化的方法來組織元件、管理狀態、處理資料流和最佳化效能。 **請考慮以下 6 種 React 設計模式:** 1. 容器和呈現模式 2. HOC(高階元件)模式 3. 複合元件模式 4. 提供者模式(使用提供者進行資料管理) 5. 狀態減速器模式 6. 元件組成模式 1. 容器和呈現模式 ---------- 在此模式中,容器元件負責管理資料和狀態邏輯。它們從外部來源獲取資料,在必要時對其進行操作,並將其作為 props 傳遞給展示元件。它們通常連接到外部服務、Redux 儲存或上下文提供者。 另一方面,展示元件僅專注於 UI 元素的展示。他們透過 props 從容器元件接收資料,並以視覺上吸引人的方式呈現它。展示元件通常是無狀態的功能元件或純元件,這使得它們更容易測試和重複使用。 **讓我們考慮一個複雜的範例來說明這些模式:** 假設我們正在建立一個社群媒體儀表板,用戶可以在其中查看朋友的貼文並與他們互動。以下是我們建立元件的方式: **容器元件(FriendFeedContainer):** 該元件將負責從 API 獲取有關好友貼文的資料、處理任何必要的資料轉換以及管理提要的狀態。它將相關資料傳遞給展示元件。 ``` import React, { useState, useEffect } from 'react'; import FriendFeed from './FriendFeed'; const FriendFeedContainer = () => { const [friendPosts, setFriendPosts] = useState([]); useEffect(() => { // Fetch friend posts from API const fetchFriendPosts = async () => { const posts = await fetch('https://api.example.com/friend-posts'); const data = await posts.json(); setFriendPosts(data); }; fetchFriendPosts(); }, []); return <FriendFeed posts={friendPosts} />; }; export default FriendFeedContainer; ``` **展示元件(FriendFeed):** 該元件將從其父容器元件 (FriendFeedContainer) 接收好友貼文資料作為 props,並以視覺上吸引人的方式呈現它們。 ``` import React from 'react'; const FriendFeed = ({ posts }) => { return ( <div> <h2>Friend Feed</h2> <ul> {posts.map(post => ( <li key={post.id}> <p>{post.content}</p> <p>Posted by: {post.author}</p> </li> ))} </ul> </div> ); }; export default FriendFeed; ``` 透過以這種方式建立我們的元件,我們將獲取資料和管理狀態的問題與 UI 渲染邏輯分開。這種分離使得我們的 React 應用程式在擴充時可以更輕鬆地進行測試、重複使用和維護。 2.HOC(高階元件)模式 ------------- 高階元件 (HOC) 是 React 中的一種模式,可讓您跨多個元件重複使用元件邏輯。它們是接受元件並傳回具有附加功能的新元件的函數。 為了示範 HOC 在具有 React hook 的社群媒體儀表板範例中的使用,讓我們考慮一個場景,其中您有多個元件需要從 API 取得使用者資料。您可以建立一個 HOC 來處理資料獲取並將獲取的資料作為 props 傳遞給包裝的元件,而不是在每個元件中重複取得邏輯。 這是一個基本範例: ``` import React, { useState, useEffect } from 'react'; // Define a higher-order component for fetching user data const withUserData = (WrappedComponent) => { return (props) => { const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Simulate fetching user data from an API const fetchData = async () => { try { const response = await fetch('https://api.example.com/user'); const data = await response.json(); setUserData(data); setLoading(false); } catch (error) { console.error('Error fetching user data:', error); setLoading(false); } }; fetchData(); }, []); return ( <div> {loading ? ( <p>Loading...</p> ) : ( <WrappedComponent {...props} userData={userData} /> )} </div> ); }; }; // Create a component to display user data const UserProfile = ({ userData }) => { return ( <div> <h2>User Profile</h2> {userData && ( <div> <p>Name: {userData.name}</p> <p>Email: {userData.email}</p> {/* Additional user data fields */} </div> )} </div> ); }; // Wrap the UserProfile component with the withUserData HOC const UserProfileWithUserData = withUserData(UserProfile); // Main component where you can render the wrapped component const SocialMediaDashboard = () => { return ( <div> <h1>Social Media Dashboard</h1> <UserProfileWithUserData /> </div> ); }; export default SocialMediaDashboard; ``` 在這個例子中: - `withUserData`是一個高階元件,用於處理從 API 取得使用者資料。它包裝傳遞的元件 ( `WrappedComponent` ) 並將取得的使用者資料作為 prop ( `userData` ) 提供給它。 - `UserProfile`是一個功能元件,它接收`userData`屬性並顯示使用者設定檔資訊。 - `UserProfileWithUserData`是透過使用`withUserData`包裝`UserProfile`傳回的元件。 - `SocialMediaDashboard`是主要元件,您可以在其中呈現`UserProfileWithUserData`或任何其他需要使用者資料的元件。 使用此模式,您可以輕鬆地跨社交媒體儀表板應用程式中的多個元件重複使用資料取得邏輯,而無需重複程式碼。 3. 複合元件模式 --------- React 中的複合元件模式是一種設計模式,可讓您建立協同工作以形成有凝聚力的 UI 的元件,同時仍保持明確的關注點分離並提供自訂元件行為和外觀的靈活性。 在此模式中,父元件充當一個或多個子元件(稱為「複合元件」)的容器。這些子元件協同工作以實現特定的功能或行為。複合元件的關鍵特徵是它們透過父元件彼此共享狀態和功能。 以下是使用 hooks 在 React 中實作複合元件模式的簡單範例: ``` import React, { useState } from 'react'; // Parent component that holds the compound components const Toggle = ({ children }) => { const [isOn, setIsOn] = useState(false); // Function to toggle the state const toggle = () => { setIsOn((prevIsOn) => !prevIsOn); }; // Clone the children and pass the toggle function and state to them const childrenWithProps = React.Children.map(children, (child) => { if (React.isValidElement(child)) { return React.cloneElement(child, { isOn, toggle }); } return child; }); return <div>{childrenWithProps}</div>; }; // Child component for the toggle button const ToggleButton = ({ isOn, toggle }) => { return ( <button onClick={toggle}> {isOn ? 'Turn Off' : 'Turn On'} </button> ); }; // Child component for the toggle status const ToggleStatus = ({ isOn }) => { return <p>The toggle is {isOn ? 'on' : 'off'}.</p>; }; // Main component where you use the compound components const App = () => { return ( <Toggle> <ToggleStatus /> <ToggleButton /> </Toggle> ); }; export default App; ``` 在這個例子中: - `Toggle`是保存複合元件( `ToggleButton`和`ToggleStatus` )的父元件。 - `ToggleButton`是負責渲染切換按鈕的子元件。 - `ToggleStatus`是另一個負責顯示切換狀態的子元件。 - `Toggle`元件管理狀態 ( `isOn` ) 並提供`toggle`功能來控制狀態。它克隆其子級並將`isOn`狀態和`toggle`函數作為 props 傳遞給它們。 透過使用複合元件模式,您可以建立可重複使用和可組合的元件,封裝複雜的 UI 邏輯,同時仍允許自訂和靈活性。 ### 4. Provider Pattern(使用Provider進行資料管理) React 中的提供者模式是一種設計模式,用於跨多個元件管理和共用應用程式狀態或資料。它涉及建立一個封裝狀態或資料的提供者元件,並透過 React 的上下文 API 將其提供給其後代元件。 讓我們透過一個範例來說明 React 中用於管理使用者身份驗證資料的 Provider 模式: ``` // UserContext.js import React, { createContext, useState } from 'react'; // Create a context for user data const UserContext = createContext(); // Provider component export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); // Function to login user const login = (userData) => { setUser(userData); }; // Function to logout user const logout = () => { setUser(null); }; return ( <UserContext.Provider value={{ user, login, logout }}> {children} </UserContext.Provider> ); }; export default UserContext; ``` 在這個例子中: - 我們使用 React 的`createContext`函數來建立一個名為`UserContext`上下文。此上下文將用於跨元件共享用戶資料和與身份驗證相關的功能。 - 我們定義一個`UserProvider`元件作為`UserContext`的提供者。該元件使用`useState`鉤子管理使用者狀態,並提供`login`和`logout`等方法來更新使用者狀態。 - 在`UserProvider`內部,我們用`UserContext.Provider`包裝`children` ,並將`user`狀態以及`login`和`logout`函數作為提供者的值傳遞。 - 現在,任何需要存取使用者資料或驗證相關功能的元件都可以使用`useContext`掛鉤來使用`UserContext` 。 讓我們建立一個使用上下文中的使用者資料的元件: ``` // UserProfile.js import React, { useContext } from 'react'; import UserContext from './UserContext'; const UserProfile = () => { const { user, logout } = useContext(UserContext); return ( <div> {user ? ( <div> <h2>Welcome, {user.username}!</h2> <button onClick={logout}>Logout</button> </div> ) : ( <div> <h2>Please log in</h2> </div> )} </div> ); }; export default UserProfile; ``` 在此元件中: 我們匯入`UserContext`並使用`useContext`鉤子來存取`UserProvider`提供的使用者資料和`logout`功能。 根據使用者是否登錄,我們呈現不同的 UI 元素。 最後,我們用`UserProvider`包裝我們的應用程式,以使用戶資料和身份驗證相關的功能可供所有元件使用: ``` // App.js import React from 'react'; import { UserProvider } from './UserContext'; import UserProfile from './UserProfile'; const App = () => { return ( <UserProvider> <div> <h1>My App</h1> <UserProfile /> </div> </UserProvider> ); }; export default App; ``` 透過這種方式,Provider 模式允許我們跨多個元件管理和共享應用程式狀態或資料,而無需進行 prop 鑽取,從而使我們的程式碼更乾淨、更易於維護。 --- 原文出處:https://dev.to/fpaghar/react-component-design-patterns-part-1-5f0g

尋找 coding 靈感,以及做 side project 賺錢的心得

嘿,我是 Vince --------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/az8xf61b2qxx1msfo4t5.png) 我是一名自學成才的開發人員,在新冠疫情期間改變了職業生涯。我改變是因為我想要更好的職業,喜歡編程,同時對建立有利可圖的 SaaS 副專案有著濃厚的興趣。 我能夠透過在空閒時間學習、建立小型副專案、參加黑客馬拉松以及為開發人員建立教育內容來轉換職業。 ![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1r07ajn3gysdscjdkns.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1r07ajn3gysdscjdkns.png) 此外,我於 2023 年 3 月推出的第一個簡單 SaaS 應用程式[CoverLetterGPT.xyz](http://coverlettergpt.xyz/)目前擁有 83 名客戶,每月收入 434 美元!沒什麼瘋狂的,但我仍然感到自豪。 (順便說一句,如果你想看看我是如何建造它的,它是[開源的](https://github.com/vincanger/coverlettergpt)!) ![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf1fhsgwuurkre9a7drq.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf1fhsgwuurkre9a7drq.png) 我目前還在開發[OpenSaaS.sh](http://OpenSaaS.sh) ,這是一個免費的開源 SaaS 入門模板,適用於 React 和 NodeJS,以及 Stripe、OpenAI 和 AWS S3 集成 基於這些經驗,並向其他成功的開發人員學習,我學到了一些如何尋找靈感和動力來建立東西,作為推進職業生涯或賺取額外收入的手段。 陷入 FOMO 的陷阱 ----------- 首先,如果您在社交媒體上的軟體開發人員圈子里呆了一段時間,那麼您無疑會受到副專案成功帖子和獨立黑客的每月經常性收入 (MRR) 螢幕截圖的轟炸。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iq72bvrgoelfsqtuebyo.png) 這可能會導致 FOMO(“害怕錯過”)受到嚴重打擊。 ![https://media3.giphy.com/media/MfTW6bkRhvFzbAZO1p/giphy.gif?cid=7941fdc6q8htvl3q7ulz5hxri8ev1uzynp9yctfd945e2v21&ep=v1_gifs_search1uzynp9yctfd945e2v21&ep=v1_gifs_searchsearch&ridgi.](https://media3.giphy.com/media/MfTW6bkRhvFzbAZO1p/giphy.gif?cid=7941fdc6q8htvl3q7ulz5hxri8ev1uzynp9yctfd945e2v21&ep=v1_gifs_search&rid=giphy.gif&ct=g) 對許多開發者來說,這就是夢想:建立一個有利可圖的副業專案,帶來穩定的被動收入,辭掉日常工作,環遊世界。 但這讓很多人想知道以下問題: *“開發人員如何找到在空閒時間進行開發的動力?”* *“我也是全端 Web 開發人員,為什麼我沒有任何好的 SaaS 想法?!”* 或者 *「為什麼我總是發現自己在完成最後一個專案之前就開始了一個新的副業專案?”* 嗯,我有一些建議,基本上可以歸結為這兩點: 1. 少做一點 2. 玩得更開心 讓我解釋… 找出不該做的事情 -------- 這可能看起來有悖常理,但實際上弄清楚什麼不該做將幫助你專注於你真正、真正、真正想要做的事情。 這是我從世界上最成功的投資者之一華倫巴菲特身上學到的東西。 一位粉絲向巴菲特詢問關於選擇生活中的工作的建議,他回應: - 列出 25 個人生目標 - 從最重要到最不重要的順序排列它們 - 只關注前 5 個目標 - 避免與目標 6 至 25 相關的活動。 這種方法有趣的地方在於,它鼓勵個人策略性地在優先順序較低的活動(目標 6 到 25)中取得不理想的成績。 為什麼?因為我們可以選擇將注意力集中在無數的事情上,但如果我們不專注於重要的事情,我們永遠不會有太多成就。 執行相同的過程,但使用副專案,會產生類似的結果: - 列出您擁有的所有出色的應用程式創意 - 選擇您最感興趣的前 2 個(記住,這也應該很有趣!) - 丟掉其餘的(至少現在是這樣)。 您也可以對應用程式功能執行相同的操作,並列出您的專案應具有的所有功能,但只保留前 5 個。 是時候集中註意力了。 ![https://c.tenor.com/QcmFyE7Ei_kAAAd/tenor.gif](https://c.tenor.com/QcmFyE7Ei_kAAAAd/tenor.gif) 從小事做起 ----- 到目前為止,「從小事做起」應該是顯而易見的,但人們似乎很難記住這一點。如果不是這樣,《原子習慣》這樣的書銷售不會超過 1000 萬冊 🤯 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/05auxij625650onzrfrv.png) 另外,想想有多少次我們低估了完成工作任務所需的時間。這是一個典型的案例,告訴您的團隊錯誤修復“應該只需要一天”,但最終花了一周的時間。 不過不用擔心,即使是最有經驗的高階工程師也會遇到這種情況。 因此,當你試圖保持動力時,你能做的最糟糕的事情就是給自己設定一個過於雄心勃勃的目標,並列出看似無窮無盡的待辦事項清單。 保持簡單可以讓你更輕鬆地實現你的目標,這會讓你充滿靈感,並讓你不斷迭代。 不用擔心競爭 ------ *“我有一個很棒的想法,但其他人搶先了我”* 這是你在開發者中經常聽到的藉口,它讓他們中的許多人甚至無法開始。**我的建議是根本不用擔心競爭**。 為什麼? 因為競爭是正常的,也是好的。您最終將不可避免地創造出一種可比較但不同的產品,該產品將與那些更像您(而不是像您的競爭對手)思考的客戶交談。 競爭對手也將不可避免地向您展示您不應在應用程式中複製或複製的內容。如果您看到他們的某個功能您不喜歡,或者發現自己在說“他們為什麼這樣做”,那麼您就放心了,您的應用程式可以找到自己的利基市場。 另外,以我的應用程式[CoverLetterGPT](https://coverlettergpt.xyz)為例,當我進行谷歌搜尋時,有大量贊助結果顯示在我的應用程式之前。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23r4dhzbrsc35vgrgdbd.png) 但你猜怎麼著,我的用戶數量每個月都在增加,而且我對這個應用程式幾乎沒有進行任何維護。是的,它基本上只是自行執行,即使有那麼多的競爭! --- 順便說一句,如果您正在尋找一種快速且低維護成本的方式來啟動您的下一個副專案,請查看[Open SaaS](https://opensaas.sh/) ! ![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf1fhsgwuurkre9a7drq.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf1fhsgwuurkre9a7drq.png) 它是一個完全免費、開源、功能豐富的 React + NodeJS SaaS 模板,包含 Stripe、OpenAI 應用程式範例、分析、管理儀表板和完整的文件! --- 好玩一點 ---- 沒有什麼比過於認真地對待這一切並僅僅因為你認為你應該這樣做而苦惱更糟糕的了。你是為自己做這件事,所以你應該享受這個過程。 嗯是的。尋找享受過程的方法! 在工作中享受樂趣的最佳方法之一就是**做自己感興趣的事情**。我的意思是,你*真的*有興趣。不要欺騙自己,認為你會喜歡為一個想法而努力,只是因為它可能會成功,或者因為你可能會用它給別人留下深刻的印象。您可能最終會很快失去從事該專案的靈感! 但如果你的問題是你根本沒有任何想法怎麼辦? 好吧,我的建議是要有趣並進行實驗。很多偉大的想法都是二階想法。我的意思是,它們是在處理其他事情後隨機產生的想法。 例如,我對[CoverLetterGPT](https://coverlettergpt.xyz)的想法就來自對[OpenAI API 的](https://openai.com)簡單實驗。我想知道它是如何運作的,並透過試用它,使用它來產生求職信和管理工作申請的想法似乎是一個不錯的想法,所以我就這麼做了! 在我看來,你對副業專案越有一種有趣的態度,你就會越喜歡為它們工作,這將帶來更專注的工作,甚至更多的想法。這是我在一些最好的獨立黑客(例如[Peter Levels)](https://twitter.com/levelsio)中看到的模式。我的意思是,看看令人印象深刻的 SaaS 應用程式清單! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7pg4ngejkm1jo9ky6hk.png) 永遠不要編碼 ------ 我的最後一項建議是: 休息一下! 是的,向 dev.to 和 Twitter 上的每個人展示你有多努力的衝動很強烈,但你的身心健康會受到影響。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r66fs9q192f1ioepl0vk.png) 給自己休息一下,做點其他事情,例如嗜好。還記得那些嗎? 當你休息一下時,你的潛意識可能會想出一些創造性的、鼓舞人心的想法,你可能也會感到驚訝🙂 您如何尋找建構靈感? ---------- 因此,我上面給出的提示絕不是完整的清單。將它們視為對話的開始者。 我今天的目標是展示我學到的一些東西,可能對其他人有幫助,所以如果您有其他提示、更好的建議,甚至不同意我的觀點,請在評論中告訴我們! --- 原文出處:https://dev.to/wasp/finding-the-inspiration-to-build-3p4n

使用這些 React 函式庫和雲端後端來建立全端應用程式。

今天,我們將學習如何使用 Wing 作為後端建立全端應用程式。 ![反應 + 維特 + 翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb7jf7dk9b08x042p0vl.png) 我們將使用 React 和 Vite 作為前端。 我知道還有其他框架,如 Vue、Angular 和 Next,但 React 仍然是最常見的,並且迄今為止有大量值得信賴的新創公司使用它。 如果您不知道, [React](https://github.com/facebook/react)是 Facebook 建立的開源程式庫,用於建立 Web 和本機使用者介面。正如您從儲存庫中看到的,它被超過 2040 萬開發人員使用。所以,這是值得的。 讓我們看看如何使用 Wing 作為後端。 ![豎起大拇指](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pskz2tyzodt4wnxbqa8y.gif) --- [Wing](https://git.new/wing-repo) - 一種雲端程式語言。 --------------------------------------------- ![翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n97bowkrexjk46n94bcc.png) Winglang 是一種專為雲端(又稱「面向雲端」)設計的新型開源程式語言。它允許您在雲端中建立應用程式,並且具有相當簡單的語法。 Wing 程式可以使用功能齊全的模擬器在本地執行(是的,不需要網路),也可以部署到任何雲端供應商。 ![機翼基礎設施](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eun3zd1gkp870rj57eeu.png) Wing 需要 Node `v20 or higher` 。 建立一個父目錄(我們使用的`shared-counter` )並使用 Vite 使用新的 React 應用程式設定前端。您可以使用這個 npm 指令。 ``` npm create -y vite frontend -- --template react-ts // once installed, you can check if it's running properly. cd frontend npm install npm run dev ``` 您可以使用此 npm 命令安裝 Wing。 ``` npm install -g winglang ``` 您可以使用`wing -V`驗證安裝。 Wing 還提供官方[VSCode 擴充功能](https://marketplace.visualstudio.com/items?itemName=Monada.vscode-wing)和[IntelliJ](https://plugins.jetbrains.com/plugin/22353-wing) ,後者提供語法突出顯示、補全、轉到定義和嵌入式 Wing 控制台支援。您可以在建立應用程式之前安裝它! 建立後端目錄。 ``` mkdir ~/shared-counter/backend cd ~/shared-counter/backend ``` 建立一個新的空 Wing 專案。 ``` wing new empty // This will generate three files: package.json, package-lock.json and main.w file with a simple "hello world" program wing it // to run it in the Wing simulator // The Wing Simulator will be opened in your browser and will show a map of your app with a single function. //You can invoke the function from the interaction panel and check out the result. ``` 使用指令`wing new empty`後的結構如下。 ``` bring cloud; // define a queue, a bucket, and a counter let bucket = new cloud.Bucket(); let counter = new cloud.Counter(initial: 1); let queue = new cloud.Queue(); // When a message is received in the queue -> it should be consumed // by the following closure queue.setConsumer(inflight (message: str) => { // Increment the distributed counter, the index variable will // store the value before the increment let index = counter.inc(); // Once two messages are pushed to the queue, e.g. "Wing" and "Queue". // Two files will be created: // - wing-1.txt with "Hello Wing" // - wing-2.txt with "Hello Queue" bucket.put("wing-{index}.txt", "Hello, {message}"); log("file wing-{index}.txt created"); }); ``` 您可以安裝`@winglibs/vite`來啟動開發伺服器,而不是使用`npm run dev`來啟動本機 Web 伺服器。 ``` // in the backend directory npm i @winglibs/vite ``` 您可以使用`backend/main.w`中提供的 publicEnv 將資料傳送到前端。 讓我們來看一個小例子。 ``` // backend/main.w bring vite; new vite.Vite( root: "../frontend", publicEnv: { TITLE: "Wing + Vite + React" } ); // import it in frontend // frontend/src/App.tsx import "../.winglibs/wing-env.d.ts" //You can access that value like this. <h1>{window.wing.env.TITLE}</h1> ``` 你還可以做更多: - 讀取/更新 API 路線並使用 Wing Simulator 檢查它。 - 使用後端獲取值。 - 使用`@winglibs/websockets`同步瀏覽器,它在後端部署一個 WebSocket 伺服器,您可以連接此 WebSocket 來接收即時通知。 您可以閱讀完整的逐步指南,以了解[如何使用 React 作為前端和 Wing 作為後端建立簡單的 Web 應用程式](https://www.winglang.io/docs/guides/react-vite-websockets)。測試是使用 Wing Simulator 完成的,並使用 Terraform 部署到 AWS。 部署後的AWS架構是這樣的。 ![建築學](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27awil840ktgh3jvklij.png) 為了提供開發者選擇和更好的體驗,Wing 推出了對[TypeScript (Wing)](https://www.winglang.io/docs/typescript/)等其他語言的全面支援。唯一強制性的事情是您必須安裝 Wing SDK。 這也將使控制台完全可用於本地偵錯和測試,而無需學習 Wing 語言。 Wing 甚至還有其他[指南](https://www.winglang.io/docs/category/guides),因此更容易遵循。 ![指南](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31czxehkg10ezmlpf7ac.png) 您可以閱讀[文件](https://www.winglang.io/docs)並查看[範例](https://www.winglang.io/docs/category/examples)。 您也可以在[Playground](https://www.winglang.io/play/?code=LwAvACAAVABoAGkAcwAgAGkAcwAgAHQAaABlACAAaQBtAHAAbwByAHQAIABzAHQAYQB0AGUAbQBlAG4AdAAgAGkAbgAgAFcAaQBuAGcALgAKAC8ALwAgAEgAZQByAGUAIAB3AGUAIABiAHIAaQBuAGcAIAB0AGgAZQAgAFcAaQBuAGcAIABzAHQAYQBuAGQAYQByAGQAIABsAGkAYgByAGEAcgB5ACAAdABoAGEAdAAgAAoALwAvACAAYwBvAG4AdABhAGkAbgBzACAAYQBiAHMAdAByAGEAYwB0AGkAbwBuAHMAIABvAGYAIABwAG8AcAB1AGwAYQByACAAYwBsAG8AdQBkACAAcwBlAHIAdgBpAGMAZQBzAC4ACgBiAHIAaQBuAGcAIABjAGwAbwB1AGQAOwAKAAoALwAvACAAVABoAGkAcwAgAGMAbwBkAGUAIABkAGUAZgBpAG4AZQBzACAAYQAgAGIAdQBjAGsAZQB0ACAAYQBzACAAcABhAHIAdAAgAG8AZgAgAHkAbwB1AHIAIABhAHAAcAAuAAoALwAvACAAVwBoAGUAbgAgAGMAbwBtAHAAaQBsAGkAbgBnACAAdABvACAAYQAgAHMAcABlAGMAaQBmAGkAYwAgAGMAbABvAHUAZAAgAHAAcgBvAHYAaQBkAGUAcgAKAC8ALwAgAGkAdAAgAHcAaQBsAGwAIABiAGUAIABzAHUAYgBzAHQAaQB0AHUAdABlAGQAIABiAHkAIABhAG4AIABpAG0AcABsAGUAbQBlAG4AdABhAHQAaQBvAG4AIABmAG8AcgAKAC8ALwAgAHQAaABhAHQAIABjAGwAbwB1AGQALgAgAEkALgBlACwAIABmAG8AcgAgAEEAVwBTACAAaQB0ACAAdwBpAGwAbAAgAGIAZQAgAGEAbgAgAFMAMwAgAEIAdQBjAGsAZQB0AC4ACgBsAGUAdAAgAGIAdQBjAGsAZQB0ACAAPQAgAG4AZQB3ACAAYwBsAG8AdQBkAC4AQgB1AGMAawBlAHQAKAApADsACgAKAC8ALwAgACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAKAC8ALwAgAFkAbwB1ACAAYwBhAG4AIABpAG4AdABlAHIAYQBjAHQAIAB3AGkAdABoACAAdABoAGUAIABhAHAAcAAgAGkAbgAgAHQAaABlACAAYwBvAG4AcwBvAGwAZQAgAC0ALQA%2BAAoALwAvACAACgAvAC8AIABDAGwAaQBjAGsAIABvAG4AIAB0AGgAZQAgAEYAdQBuAGMAdABpAG8AbgAsACAAYQBuAGQAIAB0AGgAZQBuACAAaQBuAHYAbwBrAGUAIABpAHQAIABpAG4AIAB0AGgAZQAKAC8ALwAgAGwAbwB3AGUAcgAgAHIAaQBnAGgAdAAgAHAAYQBuAGUAbAAsACAAbwByACAAYwBsAGkAYwBrACAAbwBuACAAdABoAGUAIABCAHUAYwBrAGUAdAAKAC8ALwAgAHQAbwAgAHMAZQBlACAAaQB0AHMAIABjAG8AbgB0AGUAbgB0AHMAIABpAG4AIAB0AGgAZQAgAHAAYQBuAGUAbAAsACAAZQB0AGMALgAKAC8ALwAgACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAhACEAIQAKAAoALwAvACAAYABpAG4AZgBsAGkAZwBoAHQAcwBgACAAcgBlAHAAcgBlAHMAZQBuAHQAIABjAG8AZABlACAAdABoAGEAdAAgAHIAdQBuAHMAIABsAGEAdABlAHIALAAgAG8AbgAKAC8ALwAgAG8AdABoAGUAcgAgAG0AYQBjAGgAaQBuAGUAcwAsACAAaQBuAHQAZQByAGEAYwB0AGkAbgBnACAAdwBpAHQAaAAgAGMAYQBwAHQAdQByAGUAZAAgAGQAYQB0AGEAIABhAG4AZAAKAC8ALwAgAHIAZQBzAG8AdQByAGMAZQBzACAAZgByAG8AbQAgAHQAaABlACAAcAByAGUALQBmAGwAaQBnAGgAdAAgAHAAaABhAHMAZQAuAAoAbABlAHQAIABoAGUAbABsAG8AXwB3AG8AcgBsAGQAIAA9ACAAaQBuAGYAbABpAGcAaAB0ACAAKAApACAAPQA%2BACAAewAKACAAIABiAHUAYwBrAGUAdAAuAHAAdQB0ACgAIgBoAGUAbABsAG8ALgB0AHgAdAAiACwAIAAiAEgAZQBsAGwAbwAsACAAVwBvAHIAbABkACEAIgApADsACgB9ADsACgAKAC8ALwAgAEkAbgBmAGwAaQBnAGgAdABzACAAYwBhAG4AIABiAGUAIABkAGUAcABsAG8AeQBlAGQAIABhAHMAIABzAGUAcgB2AGUAcgBsAGUAcwBzACAAZgB1AG4AYwB0AGkAbwBuAHMACgBuAGUAdwAgAGMAbABvAHUAZAAuAEYAdQBuAGMAdABpAG8AbgAoAGgAZQBsAGwAbwBfAHcAbwByAGwAZAApADsACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAACgAvAC8AIACRISAAUwB3AGkAdABjAGgAIABmAGkAbABlAHMAIABhAG4AZAAgAHMAZQBlACAAbwB0AGgAZQByACAAZQB4AGEAbQBwAGwAZQBzACAAdwBpAHQAaAAgAG0AbwByAGUACgAvAC8AIABlAHgAcABsAGUAbgBhAHQAaQBvAG4AcwAgAGEAYgBvAHYAZQAuAA%3D%3D)中使用 Wing 查看結構和範例。 如果你比較像輔導員。看這個! https://www.youtube.com/watch?v=wzqCXrsKWbo Wing 在 GitHub 上擁有超過 3500 個 Star,發布了 1500 多個版本,但仍未進入 v1 版本,這意味著意義重大。 去嘗試一下,做一些很酷的事情吧! https://git.new/wing-repo 星翼 ⭐️ --- 開發者生態系統不斷發展,許多開發者圍繞 React 建置了一些獨特的東西。 我不會介紹如何使用 React,因為這是一個非常廣泛的主題,我在最後貼了一些資源來幫助您學習 React。 但為了幫助您建立出色的 React 專案,我們介紹了 25 個開源專案,您可以使用它們來使您的工作更輕鬆。 這將有大量的資源、想法和概念。 我甚至會給你一些學習資源,以及一些產品的專案範例來學習 React。 一切都是免費的,而且只有 React。 讓我們涵蓋這一切! --- 1. [Mantine Hooks](https://www.npmjs.com/package/@mantine/hooks) - 用於狀態和 UI 管理的 React hooks。 -------------------------------------------------------------------------------------------- ![曼丁鉤子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9gxhpt4zpmxgg2cfbqi.png) 這可能不是專門針對 React 的,但是您可以使用這些鉤子來使您的工作更輕鬆。這些鉤子隨時可用,每個鉤子都有許多選項。 如果我必須評價的話,這將是每個人都可以使用的最有用的專案,而不是從頭開始編寫程式碼。 相信我,獲得 60 多個 Hooks 是一件大事,因為他們有一個簡單的方法讓您可以透過簡單的文件查看每個 Hooks 的演示。 開始使用以下 npm 指令。 ``` npm install @mantine/hooks ``` 這就是如何使用`useScrollIntoView`作為 mantine 掛鉤的一部分。 ``` import { useScrollIntoView } from '@mantine/hooks'; import { Button, Text, Group, Box } from '@mantine/core'; function Demo() { const { scrollIntoView, targetRef } = useScrollIntoView<HTMLDivElement>({ offset: 60, }); return ( <Group justify="center"> <Button onClick={() => scrollIntoView({ alignment: 'center', }) } > Scroll to target </Button> <Box style={{ width: '100%', height: '50vh', backgroundColor: 'var(--mantine-color-blue-light)', }} /> <Text ref={targetRef}>Hello there</Text> </Group> ); } ``` 它們幾乎擁有從本地儲存到分頁、滾動視圖、交叉點,甚至一些非常酷的實用程式(例如滴管和文字選擇)的所有功能。這實在太有幫助了! ![滴管](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pighzv57fvyp5uxvw8dz.png) 您可以閱讀[文件](https://mantine.dev/hooks/use-click-outside/)。 如果您正在尋找更多選項,您也可以使用[替代庫](https://antonioru.github.io/beautiful-react-hooks/)。 他們在 GitHub 上擁有超過 23k star,但這不僅僅是為了 hooks,因為他們是 React 的元件庫。 隨著`v7`版本的發布,它的每週下載量已超過 38 萬次,這表明它們正在不斷改進且值得信賴。 https://github.com/mantinedev/mantine Star Mantine Hooks ⭐️ --- 2. [React Grid Layout](https://github.com/react-grid-layout/react-grid-layout) - 可拖曳且可調整大小的網格佈局,具有響應式斷點。 -------------------------------------------------------------------------------------------------------- ![反應網格佈局](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pyg7g1bm1d3hvkexrnh3.png) React-Grid-Layout 是專為 React 應用程式建構的響應式網格佈局系統。 透過支援可拖曳、可調整大小和靜態小部件,它提供了使用網格的簡單解決方案。 與 Packery 或 Gridster 等類似系統不同,React-Grid-Layout 不含 jQuery,確保輕量級且高效的實作。 它與伺服器渲染應用程式的無縫整合以及序列化和恢復佈局的能力使其成為開發人員在 React 專案中使用網格佈局的寶貴工具。 開始使用以下 npm 指令。 ``` npm install react-grid-layout ``` 這就是如何使用響應式網格佈局。 ``` import { Responsive as ResponsiveGridLayout } from "react-grid-layout"; class MyResponsiveGrid extends React.Component { render() { // {lg: layout1, md: layout2, ...} const layouts = getLayoutsFromSomewhere(); return ( <ResponsiveGridLayout className="layout" layouts={layouts} breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }} cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }} > <div key="1">1</div> <div key="2">2</div> <div key="3">3</div> </ResponsiveGridLayout> ); } } ``` 您可以閱讀[文件](https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#installation)並查看[演示](https://react-grid-layout.github.io/react-grid-layout/examples/0-showcase.html)。有一系列[演示](https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#demos),甚至可以透過點擊“查看下一個範例”來獲得。 您也可以嘗試[codesandbox](https://codesandbox.io/p/devbox/github/gilbarbara/react-joyride-demo/tree/main/?embed=1)上的東西。 該專案在 GitHub 上有超過 19k+ 的星星,有超過 16k+ 的開發者使用,並且[npm 套件](https://www.npmjs.com/package/react-grid-layout)的每週下載量超過 600k+。 https://github.com/react-grid-layout/react-grid-layout 明星 React 網格佈局 ⭐️ --- 3. [React Spectrum](https://github.com/adobe/react-spectrum) - 提供出色使用者體驗的程式庫和工具的集合。 ----------------------------------------------------------------------------------- ![反應譜](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4wkgbdpd1gve36vgjne.png) React Spectrum 是一個庫和工具的集合,可幫助您建立自適應、可存取且強大的使用者體驗。 它們提供了太多的東西,以至於很難在一篇文章中涵蓋所有內容。 總的來說,他們提供了這四個庫。 ![反應譜](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m97vdq3x7nllmhyjy7p9.png) - [反應譜](https://react-spectrum.adobe.com/react-spectrum/index.html) - [React Stately](https://react-spectrum.adobe.com/react-stately/index.html) - 一組龐大的 React Hooks,為您的設計系統提供跨平台狀態管理。 - [反應詠嘆調](https://react-spectrum.adobe.com/react-aria/index.html) - [國際化](https://react-spectrum.adobe.com/internationalized/index.html) 我們將了解一些有關 React Aria 的內容,它是一個無樣式 React 元件和鉤子庫,可幫助您為應用程式建立可存取的、高品質的 UI 元件。 它經過了各種設備、互動方式和輔助技術的精心測試,以確保為所有用戶提供最佳體驗。 開始使用以下 npm 指令。 ``` npm i react-aria-components ``` 這就是建立自訂`select`的方法。 ``` import {Button, Label, ListBox, ListBoxItem, Popover, Select, SelectValue} from 'react-aria-components'; <Select> <Label>Favorite Animal</Label> <Button> <SelectValue /> <span aria-hidden="true">▼</span> </Button> <Popover> <ListBox> <ListBoxItem>Cat</ListBoxItem> <ListBoxItem>Dog</ListBoxItem> <ListBoxItem>Kangaroo</ListBoxItem> </ListBox> </Popover> </Select> ``` 相信我,出於學習目的,這是一座金礦。 ![選擇的設計結構](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndy61o8vtjjbq78e8vl8.png) 他們使用自己強大的[40 多個樣式元件](https://opensource.adobe.com/spectrum-css/),這比通常提供的要多得多。他們也有自己的一套[設計系統,](https://spectrum.adobe.com/)例如字體、UI、版面、動作等等。 ![造型元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a047jcb2ou7h057yf2d4.png) ![造型元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1w5jq1vfbhd6o9c9ehm.png) 您可以詳細了解[Spectrum](https://react-spectrum.adobe.com/index.html)及其[架構](https://react-spectrum.adobe.com/architecture.html)。 他們在 GitHub 上擁有超過 11,000 顆星,這表明了他們的質量,儘管他們並不廣為人知。研究它們可以為您建立圖書館提供寶貴的見解。 https://github.com/adobe/react-spectrum Star React Spectrum ⭐️ --- 4.[保留 React](https://github.com/StaticMania/keep-react) - Tailwind CSS 和 React.js 的 UI 元件庫。 ------------------------------------------------------------------------------------------- ![保持反應](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5s2z1xig75on0j2gjt1g.png) Keep React 是一個基於 Tailwind CSS 和 React.js 建立的開源元件庫。它提供了一組多功能的預先設計的 UI 元件,使開發人員能夠簡化現代、響應式且具有視覺吸引力的 Web 應用程式的建立。 開始使用以下 npm 指令。 ``` npm i keep-react ``` 這就是使用時間軸的方法。 ``` "use client"; import { Timeline } from "keep-react"; import { CalendarBlank } from "phosphor-react"; export const TimelineComponent = () => { return ( <Timeline horizontal={true}> <Timeline.Item> <Timeline.Point icon={<CalendarBlank size={16} />} /> <Timeline.Content> <Timeline.Title>Keep Library v1.0.0</Timeline.Title> <Timeline.Time>Released on December 2, 2021</Timeline.Time> <Timeline.Body> Get started with dozens of web components and interactive elements. </Timeline.Body> </Timeline.Content> </Timeline.Item> <Timeline.Item> <Timeline.Point icon={<CalendarBlank size={16} />} /> <Timeline.Content> <Timeline.Title>Keep Library v1.1.0</Timeline.Title> <Timeline.Time>Released on December 23, 2021</Timeline.Time> <Timeline.Body> Get started with dozens of web components and interactive elements. </Timeline.Body> </Timeline.Content> </Timeline.Item> <Timeline.Item> <Timeline.Point icon={<CalendarBlank size={16} />} /> <Timeline.Content> <Timeline.Title>Keep Library v1.3.0</Timeline.Title> <Timeline.Time>Released on January 5, 2022</Timeline.Time> <Timeline.Body> Get started with dozens of web components and interactive elements. </Timeline.Body> </Timeline.Content> </Timeline.Item> </Timeline> ); } ``` 輸出如下。 ![時間軸元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v22pagugp45z68jap3en.png) 流暢的小動畫讓這一切都是值得的,如果你想快速建立一個 UI,沒有任何麻煩,你可以使用它。 ![上傳](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfy9f9w0nc6ipn6wigil.png) ![通知](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zpwcnozi5ye3wpnev1g.png) 您可以閱讀[文件](https://react.keepdesign.io/docs/getting-started/Introduction)並查看[故事書](https://react-storybook.keepdesign.io/?path=/docs/components-accordion--docs)以進行詳細的使用測驗。 該專案在 GitHub 上有超過 1000 顆星,而且它的一些元件使用起來非常方便。 https://github.com/StaticMania/keep-react Star Keep React ⭐️ --- 5. [React Content Loader](https://github.com/danilowoz/react-content-loader) - SVG 支援的元件,可輕鬆建立骨架載入。 --------------------------------------------------------------------------------------------------- ![反應內容載入器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8g2yc0zush5vfgwo6hv.png) 該專案為您提供了一個由 SVG 驅動的元件,可以輕鬆建立佔位符載入(如 Facebook 的卡片載入)。 在載入狀態期間使用骨架來向使用者指示內容仍在載入。 總的來說,這是一個非常方便的專案,可以增強整體使用者體驗。 開始使用以下 npm 指令。 ``` npm i react-content-loader --save ``` 您可以這樣使用它。 ``` import React from "react" import ContentLoader from "react-content-loader" const MyLoader = (props) => ( <ContentLoader speed={2} width={400} height={160} viewBox="0 0 400 160" backgroundColor="#f3f3f3" foregroundColor="#ecebeb" {...props} > <rect x="48" y="8" rx="3" ry="3" width="88" height="6" /> <rect x="48" y="26" rx="3" ry="3" width="52" height="6" /> <rect x="0" y="56" rx="3" ry="3" width="410" height="6" /> <rect x="0" y="72" rx="3" ry="3" width="380" height="6" /> <rect x="0" y="88" rx="3" ry="3" width="178" height="6" /> <circle cx="20" cy="20" r="20" /> </ContentLoader> ) export default MyLoader ``` ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnvqlf6fmg2fayd29ojr.png) 您甚至可以拖曳單一骨架或使用為 Facebook 和 Instagram 等不同社群媒體預先定義的骨架。 您可以閱讀[文件](https://github.com/danilowoz/react-content-loader?tab=readme-ov-file#gettingstarted)並查看[演示](https://skeletonreact.com/)。 該專案在 GitHub 上擁有 13k+ Stars,並在 GitHub 上有 45k+ 開發人員使用。 https://github.com/danilowoz/react-content-loader Star React 內容載入器 ⭐️ --- 6. [React PDF](https://github.com/diegomura/react-pdf) - 使用 React 建立 PDF 檔案。 ---------------------------------------------------------------------------- ![反應 pdf](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jd7sz8eqda09rgjpf13.png) 該套件用於使用 React 建立 PDF。 開始使用以下 npm 指令。 ``` npm install @react-pdf/renderer --save ``` 您可以這樣使用它。 ``` import React from 'react'; import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer'; // Create styles const styles = StyleSheet.create({ page: { flexDirection: 'row', backgroundColor: '#E4E4E4', }, section: { margin: 10, padding: 10, flexGrow: 1, }, }); // Create Document Component const MyDocument = () => ( <Document> <Page size="A4" style={styles.page}> <View style={styles.section}> <Text>Section #1</Text> </View> <View style={styles.section}> <Text>Section #2</Text> </View> </Page> </Document> ); ``` ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb5fpfzijv3g5fi5utmw.png) ![輸出pdf分頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f46t80n0redm14icia1r.png) 您可以閱讀[文件](https://react-pdf.org/)並查看[演示](https://react-pdf.org/repl)。 React-pdf 現在提供了一個名為`usePDF`的鉤子,可以透過 React hook API 存取所有 PDF 建立功能。如果您需要更多控製文件的呈現方式或更新頻率,這非常有用。 ``` const [instance, update] = usePDF({ document }); ``` 該專案在 GitHub 上有 13k+ Stars,有超過 270 個版本,[每週下載量超過 400k](https://www.npmjs.com/package/@react-pdf/renderer) ,這是一個好兆頭。 https://github.com/diegomura/react-pdf Star React PDF ⭐️ --- 7. [Recharts](https://github.com/recharts/recharts) - 使用 React 和 D3 建立的重新定義的圖表庫。 -------------------------------------------------------------------------------- ![重新繪製圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6817tmlix6n7wtgp1yq.png) 該庫的主要目的是幫助您輕鬆地在 React 應用程式中編寫圖表。 Recharts 的主要原則是。 1. 只需使用 React 元件進行部署即可。 2. 原生 SVG 支持,輕量級,僅依賴一些 D3 子模組。 3. 聲明性元件、圖表元件純粹是表示性的。 開始使用以下 npm 指令。 ``` npm install recharts ``` 您可以這樣使用它。 ``` <LineChart width={500} height={300} data={data} accessibilityLayer> <XAxis dataKey="name"/> <YAxis/> <CartesianGrid stroke="#eee" strokeDasharray="5 5"/> <Line type="monotone" dataKey="uv" stroke="#8884d8" /> <Line type="monotone" dataKey="pv" stroke="#82ca9d" /> <Tooltip/> </LineChart> ``` ![輸出](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqtp999q1ahq8ajmvuwf.png) 您可以閱讀[文件](https://recharts.org/en-US/guide)並查看有關[Storybook](https://recharts.org/en-US/storybook)的更多資訊。 他們提供了大量的選項來自訂它,這就是開發人員喜歡它的原因。他們也提供一般常見問題的[wiki](https://github.com/recharts/recharts/wiki)頁面。 您也可以在此處的codesandbox 上嘗試。 https://codesandbox.io/embed/kec3v?view=Editor+%2B+Preview&module=%2Fsrc%2Findex.tsx 該專案在 GitHub 上有 22k+ Stars,有 200k+ 開發人員使用。 https://github.com/recharts/recharts 明星 Recharts ⭐️ --- 8. [React Joyride](https://github.com/gilbarbara/react-joyride) - 在您的應用程式中建立導遊。 ------------------------------------------------------------------------------- ![反應兜風](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ph7rt2bxqbxi67r47on8.png) ![反應兜風](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ov4wzohwszgv5v06cin4.png) 導覽是向新用戶展示您的應用程式或解釋新功能的絕佳方式。它改善了用戶體驗並可以創造個人化的觸感。 開始使用以下 npm 指令。 ``` npm i react-joyride ``` 您可以這樣使用它。 ``` import React, { useState } from 'react'; import Joyride from 'react-joyride'; /* * If your steps are not dynamic you can use a simple array. * Otherwise you can set it as a state inside your component. */ const steps = [ { target: '.my-first-step', content: 'This is my awesome feature!', }, { target: '.my-other-step', content: 'This another awesome feature!', }, ]; export default function App() { // If you want to delay the tour initialization you can use the `run` prop return ( <div> <Joyride steps={steps} /> ... </div> ); } ``` 它們還提供[元件列表](https://docs.react-joyride.com/custom-components)以及自訂預設用戶介面的簡單方法。 您可以閱讀[文件](https://docs.react-joyride.com/)並查看[演示](https://react-joyride.com/)。 您也可以嘗試[codesandbox](https://codesandbox.io/p/devbox/github/gilbarbara/react-joyride-demo/tree/main/?embed=1)上的東西。 他們在 GitHub 上有超過 6k 顆星,npm 套件每週下載量超過 25 萬次。 https://github.com/gilbarbara/react-joyride Star React Joyride ⭐️ --- 9. [SVGR](https://github.com/gregberge/svgr) - 將 SVG 轉換為 React 元件。 ------------------------------------------------------------------ ![svgr](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94hpre3yl3ttu5zdexsv.png) SVGR 是一個將 SVG 轉換為 React 元件的通用工具。 它需要一個原始的 SVG 並將其轉換為隨時可用的 React 元件。 開始使用以下 npm 指令。 ``` npm install @svgr/core ``` 例如,您採用這個 SVG。 ``` <?xml version="1.0" encoding="UTF-8"?> <svg width="48px" height="1px" viewBox="0 0 48 1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" > <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch --> <title>Rectangle 5</title> <desc>Created with Sketch.</desc> <defs></defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="19-Separator" transform="translate(-129.000000, -156.000000)" fill="#063855" > <g id="Controls/Settings" transform="translate(80.000000, 0.000000)"> <g id="Content" transform="translate(0.000000, 64.000000)"> <g id="Group" transform="translate(24.000000, 56.000000)"> <g id="Group-2"> <rect id="Rectangle-5" x="25" y="36" width="48" height="1"></rect> </g> </g> </g> </g> </g> </g> </svg> ``` 執行SVGR後,將轉換為. ``` import * as React from 'react' const SvgComponent = (props) => ( <svg width="1em" height="1em" viewBox="0 0 48 1" {...props}> <path d="M0 0h48v1H0z" fill="currentColor" fillRule="evenodd" /> </svg> ) export default SvgComponent ``` 它使用[SVGO](https://github.com/svg/svgo)優化 SVG,並使用 Prettier 格式化程式碼。 將 HTML 轉換為 JSX 需要幾個步驟: 1. 將 SVG 轉換為 HAST (HTML AST) 2. 將 HAST 轉換為 Babel AST (JSX AST) 3. 使用 Babel 轉換 AST(重新命名屬性、更改屬性值…) 您可以在[Playground](https://react-svgr.com/playground/)閱讀[文件](https://react-svgr.com/docs/getting-started)並檢查內容。 該專案在 GitHub 上擁有 10k+ Stars,有超過 800 萬開發者使用,npm 上每週下載量超過 800k。 https://github.com/gregberge/svgr 明星 SVGR ⭐️ --- 10. [React Sortable Tree](https://github.com/frontend-collective/react-sortable-tree) - 用於巢狀資料和層次結構的拖放可排序元件。 ------------------------------------------------------------------------------------------------------------ ![反應可排序樹](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/907c4rnmev2wx1abq0r7.png) 一個 React 元件,支援對分層資料進行拖放排序。 ![反應可排序樹](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4tm32vuteqaw5m7crag.png) 開始使用以下 npm 指令。 ``` npm install react-sortable-tree --save ``` 您可以這樣使用它。 ``` import React, { Component } from 'react'; import SortableTree from 'react-sortable-tree'; import 'react-sortable-tree/style.css'; // This only needs to be imported once in your app export default class Tree extends Component { constructor(props) { super(props); this.state = { treeData: [ { title: 'Chicken', children: [{ title: 'Egg' }] }, { title: 'Fish', children: [{ title: 'fingerline' }] }, ], }; } render() { return ( <div style={{ height: 400 }}> <SortableTree treeData={this.state.treeData} onChange={treeData => this.setState({ treeData })} /> </div> ); } } ``` 檢查由此獲得的各種[道具選項](https://github.com/frontend-collective/react-sortable-tree?tab=readme-ov-file#props)和[主題](https://github.com/frontend-collective/react-sortable-tree?tab=readme-ov-file#featured-themes)。 您可以閱讀[文件](https://github.com/frontend-collective/react-sortable-tree?tab=readme-ov-file#getting-started)並查看[Storybook](https://frontend-collective.github.io/react-sortable-tree/?path=/story/basics--minimal-implementation) ,以獲取一些基本和高級功能的演示。 它可能不會被積極維護(仍然沒有存檔),因此您也可以使用[維護的 fork 版本](https://github.com/nosferatu500/react-sortable-tree)。 該專案在 GitHub 上擁有超過 4,500 個 Star,並被超過 5,000 名開發人員使用。 https://github.com/frontend-collective/react-sortable-tree Star React 可排序樹 ⭐️ --- 11. [React Hot Toast](https://github.com/timolins/react-hot-toast) - 冒煙的 Hot React 通知。 -------------------------------------------------------------------------------------- ![反應熱吐司](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lw4veo990lspkchhwz64.png) React Hot Toast 透過簡單的自訂選項提供了驚人的 🔥 預設體驗。它利用 Promise API 進行自動加載,確保平穩過渡。 它重量輕,不到 5kb,但仍然可以存取,同時為開發人員提供了像`useToaster()`這樣的無頭鉤子。 首先將 Toaster 加入到您的應用程式中。它將負責渲染發出的所有通知。現在您可以從任何地方觸發 toast() ! 開始使用以下 npm 指令。 ``` npm install react-hot-toast ``` 這就是它的易用性。 ``` import toast, { Toaster } from 'react-hot-toast'; const notify = () => toast('Here is your toast.'); const App = () => { return ( <div> <button onClick={notify}>Make me a toast</button> <Toaster /> </div> ); }; ``` ![主題選項](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl8ezjabacdllw8qnd41.png) ![主題選項](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zksldf8goqbytcuumhac.png) 他們有很多自訂選項,但`useToaster()`掛鉤為您提供了一個無頭系統,可以為您管理通知狀態。這使得建立您的通知系統變得更加容易。 您可以閱讀[文件](https://react-hot-toast.com/docs)、[樣式指南](https://react-hot-toast.com/docs/styling)並查看[示範](https://react-hot-toast.com/)。 該專案在 GitHub 上有 8k+ Stars,有 230k+ 開發者使用。 https://github.com/timolins/react-hot-toast Star React Hot Toast ⭐️ --- 12. [Payload](https://github.com/payloadcms/payload) - 建立現代後端+管理 UI 的最佳方式。 -------------------------------------------------------------------------- ![有效負載](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xev60f07ilzqlfdwni0p.png) Payload 是一個無頭 CMS 和應用程式框架。它旨在促進您的開發過程,但重要的是,當您的應用程式變得更加複雜時,不要妨礙您。 Payload 沒有黑魔法,完全開源,它既是一個應用程式框架,也是一個無頭 CMS。它確實是適用於 TypeScript 的 Rails,並且您會獲得一個管理面板。您可以使用此[YouTube 影片](https://www.youtube.com/watch?v=In_lFhzmbME)了解有關 Payload 的更多資訊。 https://www.youtube.com/watch?v=In\_lFhzmbME 您可以透過使用Payload來了解[其中涉及的概念](https://payloadcms.com/docs/getting-started/concepts)。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nqn1uqupsdkexoq913mm.png) 有效負載透過您選擇的資料庫適配器與您的資料庫進行互動。目前,Payload 正式支援兩種資料庫適配器: 1. MongoDB 與 Mongoose 2. Postgres 帶毛毛雨 開始使用以下命令。 ``` npx create-payload-app@latest ``` 您必須產生 Payload 金鑰並更新`server.ts`以初始化 Payload。 ``` import express from 'express' import payload from 'payload' require('dotenv').config() const app = express() const start = async () => { await payload.init({ secret: process.env.PAYLOAD_SECRET, express: app, }) app.listen(3000, async () => { console.log( "Express is now listening for incoming connections on port 3000." ) }) } start() ``` ![使用 nextjs 進行有效負載](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghnnf34k70hpb0zjsf5f.png) 您可以閱讀[文件](https://payloadcms.com/docs/getting-started/what-is-payload)並查看[演示](https://demo.payloadcms.com/?_gl=1*9x0za3*_ga*NzEzMzkwNzIuMTcxMDE2NDk1MA..*_ga_FLQ5THRMZQ*MTcxMDE2NDk1MC4xLjEuMTcxMDE2NDk1MS4wLjAuMA..)。 他們還提供與 Payload + Stripe 無縫整合的[電子商務模板](https://github.com/payloadcms/payload/tree/main/templates/ecommerce)。此範本具有令人驚嘆的、功能齊全的前端,包括購物車、結帳流程、訂單管理等元件。 Payload 在 GitHub 上擁有 18k+ Stars,並且有超過 290 個版本,因此它們不斷改進,尤其是在資料庫支援方面。 https://github.com/payloadcms/payload 明星有效負載 ⭐️ --- 13. [React Player](https://github.com/cookpete/react-player) - 用於播放各種 URL 的 React 元件。 ------------------------------------------------------------------------------------- ![反應玩家](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/immw7vlgrdfbfxgts0a0.png) 用於播放各種 URL 的 React 元件,包括檔案路徑、YouTube、Facebook、Twitch、SoundCloud、Streamable、Vimeo、Wistia、Mixcloud、DailyMotion 和 Kaltura。您可以看到[支援的媒體](https://github.com/cookpete/react-player?tab=readme-ov-file#supported-media)清單。 ReactPlayer 的維護工作由 Mux 接管,這使它們成為一個不錯的選擇。 開始使用以下 npm 指令。 ``` npm install react-player ``` 您可以這樣使用它。 ``` import React from 'react' import ReactPlayer from 'react-player' // Render a YouTube video player <ReactPlayer url='https://www.youtube.com/watch?v=LXb3EKWsInQ' /> // If you only ever use one type, use imports such as react-player/youtube to reduce your bundle size. // like this: import ReactPlayer from 'react-player/youtube' ``` 您也可以使用`react-player/lazy`為您傳入的URL 延遲載入適當的播放器。這會為您的輸出加入幾個reactPlayer 區塊,但會減少主包的大小。 ``` import React from 'react' import ReactPlayer from 'react-player/lazy' // Lazy load the YouTube player <ReactPlayer url='https://www.youtube.com/watch?v=ysz5S6PUM-U' /> ``` 您可以閱讀[文件](https://github.com/cookpete/react-player?tab=readme-ov-file#props)並查看[演示](https://cookpete.github.io/react-player/)。他們提供了大量的選項,包括加入字幕並以簡單的方式使其響應。 它們在 GitHub 上擁有超過 8000 顆星,被超過 135,000 名開發人員使用,並且 npm 軟體包[每週的下載量超過 800k](https://www.npmjs.com/package/react-player) 。 https://github.com/cookpete/react-player 明星 React 播放器 ⭐️ --- 14. [Victory](https://github.com/FormidableLabs/victory) - 用於建立互動式資料視覺化的 React 元件。 ---------------------------------------------------------------------------------- ![勝利](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dbayfgbrutvffkk2slja.png) Victory 是一個可組合 React 元件的生態系統,用於建立互動式資料視覺化。 ![元件類型](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ua3jegboex4n21aid20.png) 開始使用以下 npm 指令。 ``` npm i --save victory ``` 您可以這樣使用它。 ``` <VictoryChart domainPadding={{ x: 20 }} > <VictoryHistogram style={{ data: { fill: "#c43a31" } }} data={sampleHistogramDateData} bins={[ new Date(2020, 1, 1), new Date(2020, 4, 1), new Date(2020, 8, 1), new Date(2020, 11, 1) ]} /> </VictoryChart> ``` 這就是它的渲染方式。他們還提供通常有用的動畫和主題選項。 ![勝利圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wdxztxui9zjtue0fz1jo.png) 您可以閱讀[文件](https://commerce.nearform.com/open-source/victory/docs)並按照[教學](https://commerce.nearform.com/open-source/victory/docs/native)開始。他們提供大約 15 種不同的圖表選項。 它也可用於[React Native(文件)](https://commerce.nearform.com/open-source/victory/docs/native) ,所以這是一個優點。我還建議您查看他們的常見[問題解答](https://commerce.nearform.com/open-source/victory/docs/faq#frequently-asked-questions-faq),其中描述了常見問題的程式碼解決方案和解釋,例如樣式、註釋(標籤)、處理軸。 該專案在 GitHub 上擁有 10k+ Stars,並在 GitHub 上有 23k+ 開發人員使用。 https://github.com/FormidableLabs/victory 勝利之星 ⭐️ --- 15. [React Slick](https://github.com/akiran/react-slick) - React 輪播元件。 ---------------------------------------------------------------------- ![反應圓滑](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4fn2aafcxs281yliyyv0.png) React Slick 是一個使用 React 建構的輪播元件。它是一個光滑的旋轉木馬的反應端口 開始使用以下 npm 指令。 ``` npm install react-slick --save ``` 這是使用自訂分頁的方法。 ``` import React, { Component } from "react"; import Slider from "react-slick"; import { baseUrl } from "./config"; function CustomPaging() { const settings = { customPaging: function(i) { return ( <a> <img src={`${baseUrl}/abstract0${i + 1}.jpg`} /> </a> ); }, dots: true, dotsClass: "slick-dots slick-thumb", infinite: true, speed: 500, slidesToShow: 1, slidesToScroll: 1 }; return ( <div className="slider-container"> <Slider {...settings}> <div> <img src={baseUrl + "/abstract01.jpg"} /> </div> <div> <img src={baseUrl + "/abstract02.jpg"} /> </div> <div> <img src={baseUrl + "/abstract03.jpg"} /> </div> <div> <img src={baseUrl + "/abstract04.jpg"} /> </div> </Slider> </div> ); } export default CustomPaging; ``` ![自訂分頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hh3qtgnftoapsrdx8w4y.png) 您可以閱讀有關可用的[prop 選項](https://react-slick.neostack.com/docs/api)和[方法](https://react-slick.neostack.com/docs/api#methods)的資訊。 您可以閱讀[文件](https://react-slick.neostack.com/docs/get-started)和所有帶有程式碼和輸出[的範例集](https://react-slick.neostack.com/docs/example/)。 他們在 GitHub 上有超過 11k 顆星,並且有超過 36 萬開發者在 GitHub 上使用它。 https://github.com/akiran/react-slick Star React Slick ⭐️ --- 16. [Medusa](https://github.com/medusajs/medusa) - 數位商務的建構模組。 ------------------------------------------------------------- ![美杜莎](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7vd1qsx7l1jdsz2cnq0.png) Medusa 是一組商務模組和工具,可讓您建立豐富、可靠且高效能的商務應用程式,而無需重新發明核心商務邏輯。 這些模組可以客製化並用於建立高級電子商務商店、市場或任何需要基礎商務原語的產品。所有模組都是開源的,可以在 npm 上免費取得。 開始使用以下 npm 指令。 ``` npm install medusa-react @tanstack/[email protected] @medusajs/medusa ``` 將其包含在`app.ts`中。 只有 MedusaProvider 的子級才能從其鉤子中受益。因此,Storefront 元件及其子元件現在可以使用 Medusa React 公開的鉤子。 ``` import { MedusaProvider } from "medusa-react" import Storefront from "./Storefront" import { QueryClient } from "@tanstack/react-query" import React from "react" const queryClient = new QueryClient() const App = () => { return ( <MedusaProvider queryClientProviderProps={{ client: queryClient }} baseUrl="http://localhost:9000" > <Storefront /> </MedusaProvider> ) } export default App ``` 例如,這就是您如何使用突變來建立購物車。 ``` import { useCreateCart } from "medusa-react" const Cart = () => { const createCart = useCreateCart() const handleClick = () => { createCart.mutate({}) // create an empty cart } return ( <div> {createCart.isLoading && <div>Loading...</div>} {!createCart.data?.cart && ( <button onClick={handleClick}> Create cart </button> )} {createCart.data?.cart?.id && ( <div>Cart ID: {createCart.data?.cart.id}</div> )} </div> ) } export default Cart ``` 他們提供了一套電子商務模組(大量選項),例如折扣、價目表、禮品卡等。 ![電子商務模組](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x00lbkpny66esa1yep4u.png) 它們還提供了一種簡單的管理員和客戶身份驗證方法,您可以在[文件](https://docs.medusajs.com/)中閱讀。 他們提供了[nextjs 入門模板](https://docs.medusajs.com/starters/nextjs-medusa-starter)和[Medusa React](https://docs.medusajs.com/medusa-react/overview)作為 SDK。 該專案在 GitHub 上有 22k+ Stars,有 4k+ 開發者使用。 https://github.com/medusajs/medusa 明星美杜莎 ⭐️ --- 17. [React Markdown](https://github.com/remarkjs/react-markdown) - React 的 Markdown 元件. --------------------------------------------------------------------------------------- ![反應降價](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hcl4bq3m0r415mknvv5h.png) Markdown 至關重要,使用 React 渲染它對於各種場景都非常有用。 它提供了一個 React 元件,能夠安全地將一串 Markdown 渲染到 React 元素中。您可以透過傳遞外掛程式並指定要使用的元件而不是標準 HTML 元素來自訂 Markdown 的轉換。 開始使用以下 npm 指令。 ``` npm i react-markdown ``` 您可以這樣使用它。 ``` import React from 'react' import {createRoot} from 'react-dom/client' import Markdown from 'react-markdown' import remarkGfm from 'remark-gfm' const markdown = `Just a link: www.nasa.gov.` createRoot(document.body).render( <Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown> ) ``` 等效的 JSX 是。 ``` <p> Just a link: <a href="http://www.nasa.gov">www.nasa.gov</a>. </p> ``` 他們還提供了一份[備忘錄](https://commonmark.org/help/)和一個十分鐘的逐步[教學](https://commonmark.org/help/tutorial/)。 ![教學](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2oboj1ooemoo2j9uh2d7.png) 您可以閱讀[文件](https://github.com/remarkjs/react-markdown?tab=readme-ov-file#install)並查看[演示](https://remarkjs.github.io/react-markdown/)。 該專案在 GitHub 上有 12k+ Stars,[每週下載量超過 2700k](https://www.npmjs.com/package/react-markdown) ,並被 200k+ 開發人員使用,證明了它的真正有用性。 https://github.com/remarkjs/react-markdown Star React Markdown ⭐️ --- 18. [React JSONSchema Form](https://github.com/rjsf-team/react-jsonschema-form) - 用於從 JSON Schema 建立 Web 表單。 ------------------------------------------------------------------------------------------------------------ ![反應 jsonform 模式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36bma59hylme02fg5mmi.png) `react-jsonschema-form`會自動從 JSON Schema 產生 React 表單,使其非常適合僅使用 JSON schema 為任何資料產生表單。它提供了像 uiSchema 這樣的自訂選項來自訂預設主題之外的表單外觀。 開始使用以下 npm 指令。 ``` npm install @rjsf/core @rjsf/utils @rjsf/validator-ajv8 --save ``` 您可以這樣使用它。 ``` import { RJSFSchema } from '@rjsf/utils'; import validator from '@rjsf/validator-ajv8'; const schema: RJSFSchema = { title: 'Todo', type: 'object', required: ['title'], properties: { title: { type: 'string', title: 'Title', default: 'A new task' }, done: { type: 'boolean', title: 'Done?', default: false }, }, }; const log = (type) => console.log.bind(console, type); render( <Form schema={schema} validator={validator} onChange={log('changed')} onSubmit={log('submitted')} onError={log('errors')} />, document.getElementById('app') ); ``` 他們提供[高級定制](https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/)選項,包括定制小部件。 您可以閱讀[文件](https://rjsf-team.github.io/react-jsonschema-form/docs/)並查看[即時遊樂場](https://rjsf-team.github.io/react-jsonschema-form/)。 它在 GitHub 上擁有超過 13k 個 Star,並被 5k+ 開發人員使用。他們在`v5`上發布了 190 多個版本,因此他們正在不斷改進。 https://github.com/rjsf-team/react-jsonschema-form Star React JSONSchema 表單 ⭐️ --- 19. [Craft.js](https://github.com/prevwong/craft.js) - 建立可擴充的拖放頁面編輯器。 --------------------------------------------------------------------- ![craft.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydxmz82mswa2tlk5onbs.png) 頁面編輯器可以增強使用者體驗,但從頭開始建立頁面編輯器可能會令人望而生畏。現有庫提供具有可編輯元件的預先建置編輯器,但自訂通常需要修改庫本身。 Craft.js 透過模組化頁面編輯器元件、透過拖放功能簡化自訂以及渲染管理來解決這個問題。在 React 中設計你的編輯器,無需複雜的插件系統,專注於你的特定需求和規格。 開始使用以下 npm 指令。 ``` npm install --save @craftjs/core ``` 他們還提供了有關如何入門的[簡短教程](https://craft.js.org/docs/guides/basic-tutorial)。我不會介紹它,因為它非常簡單且詳細。 您可以閱讀[文件](https://craft.js.org/docs/overview)並查看[即時演示](https://craft.js.org/)以及另一個[即時範例](https://craft.js.org/examples/basic)。 它在 GitHub 上有大約 6k+ Stars,但考慮到它們正在改進,仍然很有用。 https://github.com/prevwong/craft.js Star Craft.js ⭐️ --- 20. [Gatsby](https://github.com/gatsbyjs/gatsby) - 最好的基於 React 的框架,具有內建的效能、可擴展性和安全性。 ------------------------------------------------------------------------------------ ![蓋茲比](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybxi9gplvm2kr8abbtzy.png) Gatsby 是一個基於 React 的框架,使開發人員能夠建立閃電般快速的網站和應用程式,將動態渲染的靈活性與靜態網站生成的速度融為一體。 憑藉可自訂的 UI 和對各種資料來源的支援等功能,Gatsby 提供了無與倫比的控制和可擴展性。此外,它還可以自動進行效能最佳化,使其成為靜態網站的首選。 開始使用以下 npm 指令。 ``` npm init gatsby ``` 這就是如何在 Gatsby(反應元件)中使用`Link` 。 ``` import React from "react" import { Link } from "gatsby" const Page = () => ( <div> <p> Check out my <Link to="/blog">blog</Link>! </p> <p> {/* Note that external links still use `a` tags. */} Follow me on <a href="https://twitter.com/gatsbyjs">Twitter</a>! </p> </div> ) ``` 他們提供了一組[入門模板,](https://www.gatsbyjs.com/starters/)其中包含如何使用它、涉及的依賴項以及每個模板的演示。 ![範本](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8l35rwb1is60d5q506qu.png) 您可以閱讀有關 Gatsby 的一些[常見概念,](https://www.gatsbyjs.com/docs/conceptual/gatsby-concepts/)例如 React Hydration、Gatsby 建置流程等。 您可以閱讀[文件](https://www.gatsbyjs.com/docs/)並查看入門[教學課程](https://www.gatsbyjs.com/docs/tutorial/)。 Gatsby 在 GitHub 上擁有超過 55,000 顆星,並被超過 240,000 名開發者使用 https://github.com/gatsbyjs/gatsby 明星蓋茲比 ⭐️ --- 21. [Chat UI Kit React](https://github.com/chatscope/chat-ui-kit-react) - 在幾分鐘內使用 React 建立您的聊天 UI。 -------------------------------------------------------------------------------------------------- ![chatscope 聊天 ui 套件反應](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ynb25x1se0riwbvq5uv.png) Chatscope 的聊天 UI 工具包是一個用於開發網頁聊天應用程式的開源 UI 工具包。 儘管該專案並未廣泛使用,但這些功能對於剛剛查看該專案的初學者來說還是很有用的。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1y87b1clbi00tojxgzi.png) 開始使用以下 npm 指令。 ``` npm install @chatscope/chat-ui-kit-react ``` 這就是建立 GUI 的方法。 ``` import styles from '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css'; import { MainContainer, ChatContainer, MessageList, Message, MessageInput } from '@chatscope/chat-ui-kit-react'; <div style={{ position:"relative", height: "500px" }}> <MainContainer> <ChatContainer> <MessageList> <Message model={{ message: "Hello my friend", sentTime: "just now", sender: "Joe" }} /> </MessageList> <MessageInput placeholder="Type message here" /> </ChatContainer> </MainContainer> </div> ``` 您可以閱讀[文件](https://chatscope.io/docs/)。 故事書中有更[詳細的文件](https://chatscope.io/storybook/react/?path=/docs/documentation-introduction--docs)。 它提供了一些方便的元件,例如[`TypingIndicator`](https://chatscope.io/storybook/react/?path=/docs/components-typingindicator--docs) 、 [`Multiline Incoming`](https://chatscope.io/storybook/react/?path=/story/components-message--multiline-incoming)等等。 我知道你們中的一些人更喜歡透過部落格來了解整個結構,因此你可以閱讀使用 Chat UI Kit React 的 Rollbar 的[如何將 ChatGPT 與 React 整合](https://rollbar.com/blog/how-to-integrate-chatgpt-with-react/)。 您可以看到的一些演示: - [聊天機器人使用者介面](https://mars.chatscope.io/) - [與朋友聊天](https://chatscope.io/demo/chat-friends/)- 看看這個! ![聊天朋友演示快照](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hyhqti9yl02rludkocy.png) https://github.com/chatscope/chat-ui-kit-react Star Chat UI Kit React ⭐️ --- 22. [Botonic](https://github.com/hubtype/botonic) - 用於建立會話應用程式的 React 框架。 ------------------------------------------------------------------------- ![植物性的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxeslrg9cjbkej0hcth4.png) Botonic 是一個全端 Javascript 框架,用於建立在多個平台上執行的聊天機器人和現代對話應用程式:Web、行動和訊息應用程式(Messenger、WhatsApp、Telegram 等)。它建構在 ⚛️ React、Serverless 和 Tensorflow.js 之上。 如果您不了解對話應用程式的概念,可以在[官方部落格](https://www.hubtype.com/blog/what-are-conversational-apps)上閱讀它們。 使用 Botonic,您可以建立包含最佳文字外介面(簡單性、自然語言互動)和圖形介面(多媒體、視覺上下文、豐富互動)的會話應用程式。 這是一個強大的組合,可以提供比僅依賴文字和 NLP 的傳統聊天機器人更好的用戶體驗。 這就是 Botonic 的簡單方式。 ``` export default class extends React.Component { static async botonicInit({ input, session, params, lastRoutePath }) { await humanHandOff(session)) } render() { return ( <Text> Thanks for contacting us! One of our agents will attend you as soon as possible. </Text> ) } } ``` 它們也支援 TypeScript,所以這是一個優點。 您可以看到一些使用 Botonic 建置的[範例](https://botonic.io/examples/)及其原始程式碼。 您可以閱讀[文件](https://botonic.io/docs/welcome)以及如何[從頭開始建立會話應用程式](https://botonic.io/docs/create-convapp)。 https://github.com/hubtype/botonic Star Botonic ⭐️ --- 23. [React Flowbite](https://github.com/themesberg/flowbite-react) - 為 Flowbite 和 Tailwind CSS 建構的 React 元件. ------------------------------------------------------------------------------------------------------------ ![反應流咬](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vt1coti9k3ppmv0y28u.png) 每個人對他們想要用來建立網站的使用者介面都有不同的偏好。 Flowbite React 是 UI 元件的開源集合,在 React 中建置,具有來自 Tailwind CSS 的實用程式類,您可以將其用作使用者介面和網站的起點。 開始使用以下 npm 指令。 ``` npm i flowbite-react ``` 這是一起使用表格和鍵盤元件的方法。 ``` 'use client'; import { Kbd, Table } from 'flowbite-react'; import { MdKeyboardArrowDown, MdKeyboardArrowLeft, MdKeyboardArrowRight, MdKeyboardArrowUp } from 'react-icons/md'; function Component() { return ( <Table> <Table.Head> <Table.HeadCell>Key</Table.HeadCell> <Table.HeadCell>Description</Table.HeadCell> </Table.Head> <Table.Body className="divide-y"> <Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800"> <Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <Kbd>Shift</Kbd> <span>or</span> <Kbd>Tab</Kbd> </Table.Cell> <Table.Cell>Navigate to interactive elements</Table.Cell> </Table.Row> <Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800"> <Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <Kbd>Enter</Kbd> or <Kbd>Spacebar</Kbd> </Table.Cell> <Table.Cell>Ensure elements with ARIA role="button" can be activated with both key commands.</Table.Cell> </Table.Row> <Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800"> <Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <span className="inline-flex gap-1"> <Kbd icon={MdKeyboardArrowUp} /> <Kbd icon={MdKeyboardArrowDown} /> </span> <span> or </span> <span className="inline-flex gap-1"> <Kbd icon={MdKeyboardArrowLeft} /> <Kbd icon={MdKeyboardArrowRight} /> </span> </Table.Cell> <Table.Cell>Choose and activate previous/next tab.</Table.Cell> </Table.Row> </Table.Body> </Table> ); } ``` ![kbd 和表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnu5xqlqob72t9oxkb4k.png) 您可以閱讀[文件](https://www.flowbite-react.com/docs/getting-started/introduction)並查看[Storybook](https://storybook.flowbite-react.com/?path=/story/components-accordion--always-open)中的功能。您也可以查看[元件](https://www.flowbite-react.com/docs/components/accordion)清單。 在我看來,如果您想快速設定 UI,但又不想最終為高品質的開源專案使用預先定義的庫元件,那麼這很好。 該專案在 GitHub 上擁有超過 1,500 顆星,擁有超過 37,000 名開發者的用戶群,並受到社群的廣泛認可和信任,使其成為一個可靠的選擇。 https://github.com/themesberg/flowbite-react Star React Flowbite ⭐️ --- 24. [DND 套件](https://github.com/clauderic/dnd-kit)- 輕量級、高效能、可存取且可擴展的拖放功能。 ------------------------------------------------------------------------- ![免打擾套件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oz5m8hf4t4u4v2jzusl1.png) 這是一個強大的 React 拖放工具包,擁有可自訂的碰撞檢測、多個啟動器和自動滾動等功能。 它的設計考慮到了 React,提供了方便集成的鉤子,無需進行重大的架構更改。支援從清單到網格和虛擬化清單的各種用例,它既是動態的又是輕量級的,沒有外部相依性。 開始使用以下 npm 指令。 ``` npm install @dnd-kit/core ``` 這就是建立可拖放元件的方法。 `Example.jsx` ``` import React, {useState} from 'react'; import {DndContext} from '@dnd-kit/core'; import {Draggable} from './Draggable'; import {Droppable} from './Droppable'; function Example() { const [parent, setParent] = useState(null); const draggable = ( <Draggable id="draggable"> Go ahead, drag me. </Draggable> ); return ( <DndContext onDragEnd={handleDragEnd}> {!parent ? draggable : null} <Droppable id="droppable"> {parent === "droppable" ? draggable : 'Drop here'} </Droppable> </DndContext> ); function handleDragEnd({over}) { setParent(over ? over.id : null); } } ``` `Droppable.jsx` ``` import React from 'react'; import {useDroppable} from '@dnd-kit/core'; export function Droppable(props) { const {isOver, setNodeRef} = useDroppable({ id: props.id, }); const style = { opacity: isOver ? 1 : 0.5, }; return ( <div ref={setNodeRef} style={style}> {props.children} </div> ); } ``` `Draggable.jsx` ``` import React from 'react'; import {useDraggable} from '@dnd-kit/core'; import {CSS} from '@dnd-kit/utilities'; function Draggable(props) { const {attributes, listeners, setNodeRef, transform} = useDraggable({ id: props.id, }); const style = { // Outputs `translate3d(x, y, 0)` transform: CSS.Translate.toString(transform), }; return ( <button ref={setNodeRef} style={style} {...listeners} {...attributes}> {props.children} </button> ); } ``` 我將可拖曳元件放在可放置元件上。 ![自訂元件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cf98be5hq9am3f2s1dwv.png) 您可以閱讀[文件](https://docs.dndkit.com/)以及滑鼠和指標等[感測器的選項](https://docs.dndkit.com/introduction/installation#core-library)。 它在 GitHub 上擁有 10k+ Stars,並被 GitHub 上 47k+ 開發人員使用。 https://github.com/clauderic/dnd-kit 明星免打擾套件 ⭐️

再見 SASS 👋,歡迎回歸原生 CSS

Sass 已成為本地安裝的強大預處理器,十多年來構成了我的專案的支柱。它使我能夠有效地組織可擴展且穩定的 CSS 包。即使在今天,我仍然認為 Sass 是一個非常強大的工具。然而,當我們步入 2024 年時,不可否認 CSS 已經經歷了快速發展。曾經是 Sass 獨有的功能現在已原生整合到 CSS 中,包括變數和最新亮點:CSS 嵌套。 變數 -- 長期以來,定義變數一直被視為 SCSS 的獨特優勢,它允許集中管理許多屬性,這是 CSS 長期以來非常缺少的功能。然而如今,變數也可以以類似 Sass 的方式在 CSS 中定義。然而,一個顯著的差異是,Sass 變數只存在於預處理器上下文中,而 CSS 變數可以在瀏覽器中使用,甚至可以透過 JavaScript 動態覆寫。 ``` :root { --button-padding: 10px 20px; --button-bg-color: #007bff; --button-text-color: #ffffff; --button-border-radius: 8px; } .button { padding: var(--button-padding); background-color: var(--button-bg-color); color: var(--button-text-color); border-radius: var(--button-border-radius); border: none; cursor: pointer; transition: background-color 0.3s; } ``` CSS 嵌套 ------ 在另一個元素中定義一個元素的樣式規則的能力大大簡化了 CSS 的編寫。嵌套允許將這些選擇器分組到父選擇器中,而不是對從屬元素或偽選擇器重複使用相同的選擇器。這種技術可以產生清晰的、層次結構的、因而更有效率的程式碼庫。 隨著[瀏覽器對 CSS 巢狀的支援率](https://caniuse.com/?search=css%20nesting)超過 84%,對巢狀選擇器的支援率超過 86%,這種技術變得越來越容易使用。 ``` .blog { position: relative; padding: 1rem; background: var(--neutral-100); .blog-item { border: 1px solid var(--neutral-200); & span { font-size: 1rem; } } } ``` :is 偽類 ------ `:is`偽類透過接受選擇器清單並對與這些選擇器中的任何一個匹配的所有元素進行樣式設置,徹底改變了選擇器概念。這大大方便了 DOM 中元素的選擇和樣式設定。 ``` :is(selector1, selector2, selector3) { /* styles */ } ``` 您可以使用 :is() 來提高可讀性,同時避免使用長選擇器,而不是使用長選擇器清單。 : has() 偽類 ---------- CSS 偽類`:has()`提供了一種基於其後代選擇元素的強大方法,類似於條件樣式的應用。 ``` .hero:has(.hero-button) { background-color: var(--accent-50); } ``` 容器查詢 ---- 容器查詢被認為是自 CSS3 以來網頁設計最重要的創新。他們透過允許元素根據容器的大小進行調整來擴展響應式設計的概念。該技術使元素的設計能夠根據上下文動態變化,從而實現更靈活和更具適應性的設計。 ``` .component { --theme: dark; container-name: fancy; } @container fancy style(--theme: dark) { .fancy { /* dark styles. */ } } ``` ``` @container (min-width: 720px) { .headline { font-size: 2em; } } ``` 如果容器有變數 --theme: dark,請加入以下 CSS。 級聯層 --- 使用級聯層,我們可以透過分配自己的層(layer)來避免類別、ID等的嵌套,以獲得更高的特異性。使用`@layer` at-rule 和分層`@imports` ,我們可以建立自己的級聯層- 從低優先樣式(如重設和預設值),透過主題、框架和設計系統,到最高優先樣式(如元件、實用程式) ,並覆蓋。級聯層提供更多控制。 ``` @layer utilities { .button { padding: 0.5rem; } .button--lg { padding: 0.8rem; } } ``` SASS 的未來 -------- 這是否意味著 Sass 已經過時了?一點也不。 Mixins和函數,例如像素到rem的轉換,仍然是Sass不可替代的優勢。儘管如此,我還是決定在我的大部分專案中放棄 Sass。相反,我在 Sublime 編輯器中使用預先定義的程式碼區塊和套件,這顯著改善了我的工作流程。 再見sass? ----- 我堅信,到 2024 年,Sass 的好處,包括安裝、使用和編譯問題,將不再證明其使用的合理性。現代 CSS 的可擴展性和用戶友好性使得無需額外工具即可完成。 我的 Themex 專案展示了新 CSS 功能的組合有多強大:https://app.themexproject.com 隨著 CSS 的進步,我期待直接、直接地實施小型和大型專案。 **再見sass,謝謝你!** ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2v4zu1gxgmiul99ypn9.gif) --- 原文出處:https://dev.to/karsten_biedermann/goodbye-sass-welcome-back-native-css-cf