Vue + WebApi 小項目:構造本身的在線 Markdown 筆記本應用

Vue + WebApi 小項目:構造本身的在線 Markdown 筆記本應用

目錄

  • 概要
  • 知識點
  • 完整示例圖
  • 代碼與資源文件
  • 流程步驟

 

概要

  基於 MVP 最小可行性產品設計理念,咱們先完成一個可使用,並具有基本功能的 Markdown 筆記本應用,再進行逐步完善。css

 

知識點

  本文會指導初學者如何一步步運用 Vue 的計算屬性、雙向綁定、指令、生命週期鉤子,還有 localStorage 和異步請求等知識點。html

 

完整示例圖

 
 

代碼與資源文件

   https://github.com/liqingwen2015/MarkdownDemovue

  爲了不網絡緣由形成的問題,文中所使用的第三方庫(可本身去官方下載最新版,文章使用的是當前發佈時間最新版本的 js 文件)以及 css 文件都下載好而且已經放入裏面。ios

body {
    font-family: sans-serif;
    font-size: 16px;
    height: 100%;
    margin: 0;
    box-sizing: border-box;
  }
  
  .material-icons {
    font-size: 24px;
    line-height: 1;
    vertical-align: middle;
    margin: -3px;
    padding-bottom: 1px;
  }
  
  #app > * {
    float: left;
    display: flex;
    flex-direction: column;
    height: 100%;
  
    > * {
      flex: auto 0 0;
    }
  }
  
  .side-bar {
    background: #f8f8f8;
    width: 20%;
    box-sizing: border-box;
  }
  
  .note {
    padding: 16px;
    cursor: pointer;
  }
  
  .note:hover {
    background: #ade2ca;
  }
  
  .note .icon {
    float: right;
  }
  
  button,
  input,
  textarea {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
    box-sizing: border-box;
    outline: none !important;
  }
  
  button,
  .note.selected {
    background: orange;
    color: white;
  }
  
  button {
    border-radius: 3px;
    border: none;
    display: inline-block;
    padding: 8px 12px;
    cursor: pointer;
  }
  
  button:hover {
    background: #63c89b;
  }
  
  input {
    border: solid 2px #ade2ca;
    border-radius: 3px;
    padding: 6px 10px;
    background: #f0f9f5;
    color: #666;
  }
  
  input:focus {
    border-color: orange;
    background: white;
    color: black;
  }
  
  button,
  input {
    height: 34px;
  }
  
  .main, .preview {
    width: 40%;
  }
  
  .toolbar {
    padding: 4px;
    box-sizing: border-box;
  }
  
  .status-bar {
    color: #999;
    font-style: italic;
  }
  
  textarea {
    resize: none;
    border: none;
    box-sizing: border-box;
    margin: 0 4px;
    font-family: monospace;
  }
  
  textarea, .notes, .preview {
    flex: auto 1 1;
    overflow: auto;
  }
  
  .preview {
    padding: 12px;
    box-sizing: border-box;
    border-left: solid 4px #f8f8f8;
  }
  
  .preview p:first-child {
    margin-top: 0;
  }
  
  a {
    color: orange;
  }
  
  h1,
  h2,
  h3 {
    margin: 10px 0 4px;
    color: orange;
  }
  
  h1 {
    font-size: 2em;
  }
  
  h2 {
    font-size: 1.5em;
  }
  
  h3 {
    font-size: 1.2em;
  }
  
  h4 {
    font-size: 1.1em;
    font-weight: normal;
  }
使用的 index.css 文件

 

流程步驟

  1.先構建一個基本的 html 文件,並引入核心 js 庫。git

  這裏須要引入的第三方庫爲 vue.js、marked.js。github

<html>

<head>
    <title></title>
    <!-- 引入樣式文件 -->
    <link rel="stylesheet" href="index.css" />
</head>

<body>
    <!-- 引入 js 庫 -->
    <script src="/lib/vue.js"></script>
    <script src="/lib/marked.js"></script>

    <!-- js 代碼 -->
    <script src="index.js"></script>
</body>

</html>

 

  由於考慮到項目主要劃分爲兩塊,左邊是書寫區域,右邊爲預覽區域,<body> 塊代碼修改成:數據庫

<body>
    <!-- 引入 js 庫 -->
    <script src="lib/vue.js"></script>
    <script src="lib/marked.js"></script>

    <div id="app">
        <!-- 主區域:書寫 -->
        <section class="main"></section>

        <!-- 預覽區域 -->
        <aside class="preview"></aside>
    </div>

    <!-- js 代碼 -->
    <script src="index.js"></script>
</body>

 

  修改 js 代碼:建立 Vue 實例,並將其掛載到 DOM 元素上。axios

new Vue({
    el: '#app'
})

 

  【備註】上面的掛載方式是比較常見的一種,咱們也可使用 app.$mount('#app') 進行掛載。api

 

  2.接下來咱們使用 Vue 的雙向綁定機制控制輸入的內容和預覽的內容。跨域

  修改 html:

<body>
    <!-- 引入 js 庫 -->
    <script src="lib/vue.js"></script>
    <script src="lib/marked.js"></script>

    <div id="app">
        <!-- 主區域:書寫 -->
        <section class="main">
            <textarea v-model="editor"></textarea>
        </section>

        <!-- 預覽區域 -->
        <aside class="preview">
            {{editor}}
        </aside>
    </div>

    <!-- js 代碼 -->
    <script src="index.js"></script>
</body>

 

  修改 js,增長數據屬性:

new Vue({
    el: '#app',
    data() {
        return {
            editor: '編輯器'
        }
    }
})

 

  如今,打開 index.html 頁面,在瀏覽器頁面中的左側進行輸入就能夠在預覽窗口中同步看到輸入後的狀況。

 

  3.接下來,咱們須要對輸入的內容通過 Markdown 形式轉換,在這裏,咱們使用 Vue 的計算屬性來進行優化渲染 Markdown 的實時預覽

  修改 js:

new Vue({
    // 掛載
    el: '#app',
    
    // 數據
    data() {
        return {
            editor: '編輯器'
        }
    },

    // 計算屬性
    computed: {
        editorPreview() {
            return marked(this.editor);
        }
    }
})

 

  修改 <body>,使用 v-html 指令取代 {{ }},以這種方式來渲染 HTML 元素。

<body>
    <!-- 引入 js 庫 -->
    <script src="lib/vue.js"></script>
    <script src="lib/marked.js"></script>

    <div id="app">
        <!-- 主區域:書寫 -->
        <section class="main">
            <textarea v-model="editor"></textarea>
        </section>

        <!-- 預覽區域 -->
        <aside class="preview" v-html="editorPreview"> </aside>
    </div>

    <!-- js 代碼 -->
    <script src="index.js"></script>
</body>

 

 
運行效果圖

 

  4.保存內容

  目前,若是關閉了瀏覽器或者對頁面進行了刷新,全部內容都會丟失。因此,咱們目前使用 localStorage  的方式進行數據的保存操做。

  如今產生了一個疑問:應該何時進行保存呢?

  咱們如今使用 Vue 的偵聽器功能來對數據的改動進行保存操做,由於它能夠監聽到 editor 的每一改動操做,意思是每次輸入操做都會觸發偵聽器裏面的方法。

  修改 js:

new Vue({
    // 掛載
    el: '#app',

    // 數據
    data() {
        return {
            editor: '編輯器'
        }
    },

    // 計算屬性
    computed: {
        editorPreview() {
            return marked(this.editor);
        }
    },

    // 偵聽器
    watch: {
        editor(val) {
            localStorage.setItem('editor', this.editor);
        }
    }
})

 

  那麼如今又產生了新的疑問:應該怎樣纔可以在每次進入這個頁面時顯示以前保存的信息呢?

  如今,咱們經過利用 Vue 的生命週期鉤子(目前使用 created 鉤子)來進行數據的讀取及恢復。

  修改 js:

new Vue({
    // 掛載
    el: '#app',

    // 數據
    data() {
        return {
            editor: '編輯器',
            key: {
                editor: 'editor'
            }
        }
    },

    // 計算屬性
    computed: {
        editorPreview() {
            return marked(this.editor);
        }
    },

    // 偵聽器
    watch: {
        editor(val) {
            localStorage.setItem(this.key.editor, this.editor);
        }
    },

    // 生命週期鉤子
    created() {
        this.editor = localStorage.getItem(this.key.editor) || '第一次使用 Markdown 筆記本';
    }
})

 

  【備註】在進行修改 js 後,editor 屬性第一次加載的時候可能爲 null,這會致使整個應用出錯,因此這裏採用了默認值。

 

  5.localStorage 畢竟不是永久保存的方式,這裏我使用一種較爲簡單的方式,保存方法替換爲異步請求到 WebApi 接口保存到數據庫的方式

  修改 html,引入 axios 庫:

<script src="lib/axios.min.js"></script>

 

  同時,修改 js,增長兩個 Http 請求的方法,獲取和保存:

new Vue({
    // 掛載
    el: '#app',

    // 數據
    data() {
        return {
            editor: '',
            key: {
                editor: 'editor'
            },
            url: 'http://localhost:34473/api/markdown'  // 須要替換成本身的 API 路徑
        }
    },

    // 計算屬性
    computed: {
        editorPreview() {
            return marked(this.editor);
        }
    },

    // 偵聽器
    watch: {
        editor(val) {
            //localStorage.setItem(this.key.editor, this.editor);
            this.save();
        }
    },

    // 生命週期鉤子
    created() {
        this.load();
        // this.editor = localStorage.getItem(this.key.editor) || '第一次使用 Markdown 筆記本';
    },

    // 方法
    methods: {
        load() {
            var that = this;
            axios.get(that.url).then(function (result) {
                console.log(result.data);
                that.editor = result.data;
            });
        },
        save() {
            var that = this;
            axios.post(that.url, { content: that.editor }).then(function (result) { });
        }
    }
})

 

  新增的 API 控制器 MarkdownController.cs 的內容以下:

    [Route("api/[controller]")]
    [ApiController]
    public class MarkdownController : ControllerBase
    {
        public static MarkdownViewModel MarkdownViewModel = new MarkdownViewModel()
        {
            Content = "個人第一個 Markdown 應用"
        };

        [HttpGet]
        public ActionResult<string> Get()
        {
            return MarkdownViewModel.Content;
        }

        [HttpPost]
        public void Save([FromBody] MarkdownViewModel vm)
        {
            MarkdownViewModel = vm;
        }
    }

 

  視圖模型 MarkdownViewModel.cs 的內容以下:

    public class MarkdownViewModel
    {
        public string Content { get; set; }
    }

 

  【備註】須要自行進行 WebApi 的跨域配置,演示時進行了忽略配置  

  【備註】示例代碼可從 https://github.com/liqingwen2015/MarkdownDemo 下載

 

【切換閱讀方式】https://www.jianshu.com/p/a17033ca91d9【參考】Vue.js 2 Web Development Projects

相關文章
相關標籤/搜索