EP29 - ex1. Markdown

更新於 2024/10/06閱讀時間約 17 分鐘
看官方文件看個幾篇就好累~
終於輪到實用範例摟!
這篇要做一個Markdown編輯器,真的假的?!?

首先在開啟第二組實用練習之前,我要把先前的範例整理到一個View裡頭,先前的邏輯是 index.html ⮕ main.js ⮕ App.vue 再把畫面渲染到id=App的元素上,現在要將資料夾內容改成以下的狀況,目的是要把一些練習組件放在Views裡頭管理

raw-image

Vue Router

研究一下可以用vue router來控管一下view頁面,先來去npm安裝一下。

raw-image


安裝指令:

npm install vue-router@4

安裝完之後,要進行入口修改一下
創建Router資料夾,並建立index.js




修改入口 - main.js

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import router from './router';


// createApp(App).mount('#app')
createApp(App).use(router).mount('#app');

新增router - router/index.js

import { createRouter, createWebHistory } from 'vue-router';
import BasicExamples from '../views/BasicExamples.vue';
import PracticalExamples from '../views/PracticalExamples.vue';

const routes = [
{ path: '/basic-examples', component: BasicExamples },
{ path: '/practical-examples', component: PracticalExamples },
];

const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

修改#app - App.vue

<script setup>
import { RouterView } from 'vue-router';
</script>

<template>
<div class="app-container">
<div class="nav-container">
<div class="card">
<router-link to="/basic-examples">Basic Examples</router-link>
</div>
<div class="card">
<router-link to="/practical-examples">Practical Examples</router-link>
</div>
</div>
<div class="content-container">
<RouterView />
</div>
</div>
</template>


<style>
.app-container {
display: flex;
/* 使用 Flexbox 排版 */
width: 100%;
}

.nav-container {
display: flex;
flex-direction: column;
/* 使導航項目垂直排列 */
margin: 2rem 0;
gap: 1rem;
/* 設定導航欄的寬度 */
width: 200px;
/* 導航欄固定寬度 */
}

.card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
padding: 2rem;
text-align: center;
transition: transform 0.2s;
}

.card:hover {
transform: scale(1.05);
}

.card a {
color: #42b983;
text-decoration: none;
font-size: 1.2rem;
font-weight: bold;
}

.card a:hover {
text-decoration: underline;
}

.content-container {
/* max-width: 1200px; */
/* 最大寬度 */
width: 100%;
/* 寬度100% */
margin: 0 auto;
/* 自動左右邊距使其居中 */
padding: 20px;
/* 內邊距 */
}

@media (min-width: 1024px) {
#app {
display: block;
/* 使用 block 或其他佈局 */
/* 移除 grid-template-columns */
padding: 0 2rem;
/* 保留內邊距 */
}
}
</style>

有了router之後,邏輯變成這樣

index.html ⮕ main.js ⮕ App.vue + index.js

Vue Router 的效果與運作原理

Vue Router 是 Vue.js 的官方路由管理器,用於構建單頁應用程序 (SPA)。它的主要功能是根據當前的 URL 路徑來顯示不同的視圖組件。以下是 Vue Router 的運作過程和效果的簡要說明:

  • 初始化:應用程序啟動時,index.html 中的 div 元素設置了 id="app"。這個 div 是 Vue 應用的根容器。
  • 主入口:在 main.js 中,創建了 Vue 應用實例,並將它掛載到 #app 元素上。同時,Vue Router 被引入並使用。
  • 根組件App.vue 作為根組件,其中包含了導航欄和 RouterViewRouterView 是一個占位組件,會根據當前路由顯示相應的視圖。
  • 路由配置:在 router/index.js 中定義了路由配置,這些配置決定了 URL 對應哪個組件。
  • 導航:通過 <router-link> 元素創建的導航鏈接,可以在應用內部切換不同的路徑,從而改變 RouterView 中顯示的內容。

調整樣式和結構

為了確保內容區域在寬螢幕下顯示正常,移除不必要的樣式,並確保 #app 沒有多餘的樣式影響:

@media (min-width: 1024px) {
#app {
display: block; /* 使用 block 或其他佈局 */
/* 移除 grid-template-columns */
padding: 0 2rem; /* 保留內邊距 */
}
}

範例 - MarkDown

先安裝所需套件

// 範例 安裝套件
npm install marked
npm install lodash-es

程式碼 (60行)

<!--
A simple markdown editor.
-->

<script setup>
import { marked } from 'marked'
import { debounce } from 'lodash-es'
import { ref, computed } from 'vue'

const input = ref('# hello')

const output = computed(() => marked(input.value))

const update = debounce((e) => {
input.value = e.target.value
}, 100)
</script>

<template>
<p>Example 1:</p>
<div class="editor">
<textarea class="input" :value="input" @input="update"></textarea>
<div class="output" v-html="output"></div>
</div>
</template>

<style>
body {
margin: 0;
}

.editor {
height: 100vh;
display: flex;
}

.input,
.output {
overflow: auto;
width: 50%;
height: 100%;
box-sizing: border-box;
padding: 0 20px;
}

.input {
border: none;
border-right: 1px solid #ccc;
resize: none;
outline: none;
background-color: #f6f6f6;
font-size: 14px;
font-family: 'Monaco', courier, monospace;
padding: 20px;
}

code {
color: #f66;
}
</style>

<script setup> 部分

引入模組

<script setup>
import { marked } from 'marked' // 引入 marked 庫,用於將 Markdown 轉換為 HTML
import { debounce } from 'lodash-es' // 引入 lodash-es 的 debounce 函數,用於防止頻繁觸發輸入事件
import { ref, computed } from 'vue' // 從 Vue 中引入 ref 和 computed 函數

定義狀態和計算屬性

const input = ref('# hello')  // 定義一個 ref 變數 input,初始值為 '# hello'

const output = computed(() => marked(input.value)) // 定義一個 computed 屬性 output,值為將 input 的值轉換為 HTML 後的結果

定義更新函數

const update = debounce((e) => {
input.value = e.target.value // 定義一個 update 函數,使用 debounce 來限制頻繁觸發。當輸入框內容變化時,更新 input 的值
}, 100) // debounce 時間設置為 100 毫秒
</script>

<template> 部分

<template>
<p>Example 1:</p> <!-- 顯示一個標題 "Example 1:" -->
<div class="editor">
<textarea class="input" :value="input" @input="update"></textarea> <!-- 輸入框,綁定 input 變數,當輸入變化時觸發 update 函數 -->
<div class="output" v-html="output"></div> <!-- 輸出區域,顯示由 output 計算屬性生成的 HTML -->
</div>
</template>

<style> 部分

body {
margin: 0; // 設置 body 元素的 margin 為 0,去除預設的外邊距
}

.editor {
height: 100vh; // 設置編輯器的高度為視窗高度的 100%
display: flex; // 使用 flexbox 排版
}

.input,
.output {
overflow: auto; // 設置溢出時顯示滾動條
width: 50%; // 設置輸入和輸出區域的寬度各占 50%
height: 100%; // 設置高度為 100%
box-sizing: border-box; // 設置 box-sizing 為 border-box,包含 padding 和 border 在內的總寬度和高度
padding: 0 20px; // 設置左右 padding 為 20px
}

.input {
border: none; // 移除邊框
border-right: 1px solid #ccc; // 設置右邊框為 1px 寬的實線,顏色為 #ccc
resize: none; // 禁止調整大小
outline: none; // 移除聚焦時的外輪廓
background-color: #f6f6f6; // 設置背景顏色為 #f6f6f6
font-size: 14px; // 設置字體大小為 14px
font-family: 'Monaco', courier, monospace; // 設置字體為 Monaco, courier, monospace
padding: 20px; // 設置內邊距為 20px
}

code {
color: #f66; // 設置 code 元素的字體顏色為 #f66
}
</style>

總結

這個 Markdown 編輯器主要分為三個部分:

  1. 輸入區域:使用 <textarea> 元素來輸入 Markdown 內容,並綁定到 Vue 的 input 變數。
  2. 輸出區域:使用 <div> 元素來顯示轉換後的 HTML 內容,並綁定到 Vue 的 output 計算屬性。
  3. 樣式設置:使用 CSS 來設置輸入和輸出區域的佈局和樣式,使其在視窗中占據對稱的空間。

透過 marked 將 Markdown 轉換為 HTML,並使用 lodash-esdebounce 函數來防止頻繁觸發輸入事件,這樣可以避免性能問題。

經由import了兩個套件,以及短短的60行就實現了一個簡易的Markdown編輯器,
真的蠻有趣的!!!藉此也了解到debounce函數的用法~
然後慢慢地把範例檔案集中在這裡~Readme等有空再整理~ vue example

以下是測試Markdown的效果,大家快來玩看看吧~

raw-image





avatar-img
2會員
71內容數
分享生活趣事~
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
卡關的人生 的其他內容
使用 defineAsyncComponent 函數可實現此功能,它接受一個返回 Promise 的加載函數。在大型應用中,組件可以按需加載,並且可與 ES 模塊的動態導入結合使用。還可以使用高級選項處理加載和錯誤狀態,例如設置加載組件和超時設定。
在 Vue 中,當需要將數據從父組件傳遞到深層嵌套的子組件時,使用 props 會導致屬性過度傳遞 (Prop Drilling),這樣即使某些中間組件不需要這些數據,也必須聲明並傳遞它們。這種情況會使代碼難以維護。Provide 和 Inject 是解決這個問題的工具。
通過使用插槽,組件可以變得更加靈活和可重用,例如 <FancyButton> 可以讓父組件提供按鈕的內部內容,而 <BaseLayout> 則可以使用命名插槽來指定不同區域的內容。插槽還可以設置預設內容,當父組件未提供插槽內容時,會渲染預設內容。
當組件渲染單根元素時,這些屬性會自動添加到根元素中。如果子組件的根元素已有class或style屬性,則會與從父組件繼承的屬性合併。v-on事件監聽器也遵循相同規則。當組件嵌套時,降級屬性會自動轉發給子組件。
從 3.4 開始,推薦使用 defineModel() 巨集來自動化這個過程,讓寫法更加簡潔,支持多個 v-model 綁定,並可直接使用自定義修飾符。新方法還能同步父子組件的值,減少同步問題,使組件的開發與維護變得更方便
子組件可以使用 $emit 方法來發送自定義事件,父組件則使用 v-on 來監聽這些事件。事件參數可以通過 $emit 傳遞,並在父組件中使用內聯箭頭函數或方法接收。使用 defineEmits 可以顯式宣告事件並進行驗證,提升代碼可讀性和可維護性。
使用 defineAsyncComponent 函數可實現此功能,它接受一個返回 Promise 的加載函數。在大型應用中,組件可以按需加載,並且可與 ES 模塊的動態導入結合使用。還可以使用高級選項處理加載和錯誤狀態,例如設置加載組件和超時設定。
在 Vue 中,當需要將數據從父組件傳遞到深層嵌套的子組件時,使用 props 會導致屬性過度傳遞 (Prop Drilling),這樣即使某些中間組件不需要這些數據,也必須聲明並傳遞它們。這種情況會使代碼難以維護。Provide 和 Inject 是解決這個問題的工具。
通過使用插槽,組件可以變得更加靈活和可重用,例如 <FancyButton> 可以讓父組件提供按鈕的內部內容,而 <BaseLayout> 則可以使用命名插槽來指定不同區域的內容。插槽還可以設置預設內容,當父組件未提供插槽內容時,會渲染預設內容。
當組件渲染單根元素時,這些屬性會自動添加到根元素中。如果子組件的根元素已有class或style屬性,則會與從父組件繼承的屬性合併。v-on事件監聽器也遵循相同規則。當組件嵌套時,降級屬性會自動轉發給子組件。
從 3.4 開始,推薦使用 defineModel() 巨集來自動化這個過程,讓寫法更加簡潔,支持多個 v-model 綁定,並可直接使用自定義修飾符。新方法還能同步父子組件的值,減少同步問題,使組件的開發與維護變得更方便
子組件可以使用 $emit 方法來發送自定義事件,父組件則使用 v-on 來監聽這些事件。事件參數可以通過 $emit 傳遞,並在父組件中使用內聯箭頭函數或方法接收。使用 defineEmits 可以顯式宣告事件並進行驗證,提升代碼可讀性和可維護性。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
先學習 HTML, CSS, JavaScript 基礎觀念, 再透過實作專案,慢慢熟悉不同的語法使用方式。
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
理解一個全新的操作環境有時候可能是一個挑戰,尤其對於那些剛開始接觸VS Code的開發者來說,即便具備一定的英文閱讀能力,可能也會對這個陌生的操作環境感到徬徨和不安。不過,沒有必要擔心,我們接下來就來一起用短短的一分鐘時間,將VS Code轉換成最熟悉的中文環境吧! 安裝繁體中文語言包 由於VS
Thumbnail
因為最近想嘗試編碼風格,於是就選了一套比較"不嚴格"的輔助工具來摸索。 編輯器 VS CODE 框架 VUE3 打包工具 VITE 編碼風格 Standard 環境 version { "nodejs":"v18.18.0", "npm":"9.8.1" }
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
我們在實作中,難免會遇到在不同組件中,卻有需求相同的資料格式,因此 mixins 可以達到我們的需求,除了 data 以外也包含了 methods 可以共用,舉例來說,學生資料可能會在,班級跟社團內被使用,當我們要撰寫元件時,就可以省略多餘的 data 定義。
Thumbnail
這是為了搭建自己想要的工作流而開始的研究工作。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
先學習 HTML, CSS, JavaScript 基礎觀念, 再透過實作專案,慢慢熟悉不同的語法使用方式。
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
理解一個全新的操作環境有時候可能是一個挑戰,尤其對於那些剛開始接觸VS Code的開發者來說,即便具備一定的英文閱讀能力,可能也會對這個陌生的操作環境感到徬徨和不安。不過,沒有必要擔心,我們接下來就來一起用短短的一分鐘時間,將VS Code轉換成最熟悉的中文環境吧! 安裝繁體中文語言包 由於VS
Thumbnail
因為最近想嘗試編碼風格,於是就選了一套比較"不嚴格"的輔助工具來摸索。 編輯器 VS CODE 框架 VUE3 打包工具 VITE 編碼風格 Standard 環境 version { "nodejs":"v18.18.0", "npm":"9.8.1" }
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
我們在實作中,難免會遇到在不同組件中,卻有需求相同的資料格式,因此 mixins 可以達到我們的需求,除了 data 以外也包含了 methods 可以共用,舉例來說,學生資料可能會在,班級跟社團內被使用,當我們要撰寫元件時,就可以省略多餘的 data 定義。
Thumbnail
這是為了搭建自己想要的工作流而開始的研究工作。