2024-10-06|閱讀時間 ‧ 約 0 分鐘

EP29 - ex1. Markdown

看官方文件看個幾篇就好累~
終於輪到實用範例摟!
這篇要做一個Markdown編輯器,真的假的?!?

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

raw-image

Vue Router

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


安裝指令:

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的效果,大家快來玩看看吧~





分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.