仿MSDN的幫助系統

啟明星工作室發表於2021-03-15

作為軟體開發人員,軟體做好後,接下來就是編寫文件。我自己也是做軟體的,經常有使用者詢問軟體的安裝與使用,

我一直很喜歡微軟的MSDN幫助系統,簡介、大氣,使用方便。

網上也找了很久,感覺一直沒有合適的,

所以,花了一週時間寫了一個仿MSDN的系統 kbase(演示見  http://demo.dotnetcms.org/kbase)。

這篇文章來分析在製作這個系統遇到的幾個問題以及總結。

 

 如果分析微軟MSDN,不難發現,他的左邊是一個導航樹,中間是正文,右邊是正文的快速連結。

(1)樹導航

在選擇導航樹時,我最初考慮的是bootstrap-treeview

不管從介面還是功能上,他和MSDN的幫助系統導航樹都很像。

但是,如果我們仔細觀察MSDN,他的導航樹裡,當點選父節點時是展開子節點,

只有點選“子節點”才能才會開啟正文(參考下圖)。

但是,這個功能bootstrap treeview控制的並不是很好。

bootstrap treeview點選父節點是開啟文字,只有點選父節點前面的“+”才會展開子節點。

 

 

 

所以,最終選擇了zTree,在zTree官方給的Demo裡,有一個Outlook風格的模板,簡直就是MSDN的原型。

同時,ztree提供的介面和功能遠遠比bootstrap-treeview強大,所以很快我就選中了她。

 

要使用zTree,首先定義zTree的配置seeting,然後在程式碼裡,重新了onClick事件。

在onClick事件裡,判斷使用者點選的節點有沒有子節點,

如果有子節點,就展開子節點,

如果沒有子節點,就開啟網址。

var setting = {
    view: {
        showLine: false,
        showIcon: false,
        selectedMulti: false,
        dblClickExpand: false,
        addDiyDom: addDiyDom
    },
    data: {
        simpleData: {
            enable: true
        }
    },

    callback: {
        onClick: onClick
    }
};



function onClick(e, treeId, treeNode) {
     

    if (treeNode.children != null) {
        var zTree = $.fn.zTree.getZTreeObj("treeNav");
        zTree.expandNode(treeNode);
    }
    else {
        if (treeNode.id > 0) {
        }
        else { 
            window.location = "default.aspx?id=" + treeNode.id+"&title="+treeNode.name;
        }
    }
}

function addDiyDom(treeId, treeNode) {
    var spaceWidth = 5;
    var switchObj = $("#" + treeNode.tId + "_switch"),
    icoObj = $("#" + treeNode.tId + "_ico");
    switchObj.remove();
    icoObj.before(switchObj);

    if (treeNode.level >= 1) {
        var spaceStr = "<span style='display: inline-block;width:" + (spaceWidth * treeNode.level) + "px'></span>";
        switchObj.before(spaceStr);
    }
}

 

(2)導航樹的子節點是類別還是標題

但是,這樣又遇到第二個問題:

左邊導航樹裡的內容,到底是按照“分類”處理還是按照“新聞標題”處理。

開發過CMS(內容管理系統)的朋友都知道,一般CMS系統都是:

建立一個catetory分類,然後新聞會有一個標題title,和一個分類catID和分類表關聯。

那MSDN左邊導航樹,使用者點選的具體內容到底算“類別”還是“新聞標題”呢?

我最初的想法是算類別,左邊設想的是一張表,裡面儲存所有的導航樹“節點”,但是你能想象出來,

如果文章內容越來越多,構建導航樹維護是比較困難。

最終,我決定,MSDN導航樹,父節點都是“類別”,而葉節點才是新聞的標題,

系統實現裡,建了兩張表,這兩張表通過 SQL的union all 關鍵字進行合併,然後作為資料來源提供給zTree

select id, pId, catname as name,  orderid  from kb_cat 
union all
select     id, catid as pId, title as name,   orderid  from kb_news 

 

 

(3)編輯器選擇

 在一開始,我就定位了後臺編輯器必須使用Markdown(MD)編輯器,

原因很簡單,這個仿MSDN的系統更偏向知識的傳遞,注重的是內容而不是介面,

而傳統的HTML編寫幫助文件,會產生大量的“垃圾程式碼”,這不是我想要的。

因此,接下來就是開始尋找MD編輯器。

我最先想到的是部落格園後臺有markdown編輯器,所以看看部落格園怎麼做的吧

但是很快放棄使用部落格園的MD了,原因有2點:

(1)他的編寫和預覽是分開的,這不是我想要的,我希望左邊是錄入頁面,右邊是實時預覽。

(2)View Source頁面,天,部落格園的原始碼是全壓縮的JS, 完全看不到他引用了哪些JS。

算了,放棄把

 

接下來就是痛苦的尋找過程。

包括  幾款主流好用的markdown編輯器介紹 等,但是,都感覺差了那麼點意思,不是我想要的。

最終,皇天不負有心人,無意中點到了“葉子島”(叛道)網站,

然後看到了一個“ipandao(愛叛道)”的MD編輯器。

(題外話,這個編輯器名字太難記了,所以,軟體開發還是要取一個容易記憶的名字。)

 

點進去看看 https://pandao.github.io/editor.md/ 介面美觀,大方,左右佈局,提供實時預覽,提供自定義擴充套件,

而且內建和codemirror整合,支援程式碼高亮顯示,而且還開源,原始碼的JS裡也沒有使用太複雜的技術。

 這正是我想要的,這真的是太好了。

 

 

很快,我就把這個系統整合到仿MSDN的系統裡。同時,自定義了工具欄,移除了沒用的,只保留10來個按鈕。

下面是程式碼的實現 

        <script type="text/javascript">
            var testEditor;

            $(function () {
                testEditor = editormd("test-editormd", {
                    width: "100%",
                    height:520,
                    placeholder: "",
                    lineNumbers:true,
                    path: "../javascript/pandao-markdown/lib/", 
                    toolbarIcons: function () { 
                        return ["bold", "quote", "|", "h3", "h4", "h5", "h6", "list-ul", "list-ol", "|", "link", "image", "|", "code", "code-block", "table"]
                    },

                    imageUpload: true,
                    imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
                    imageUploadURL: "save_img.aspx",
                    saveHTMLToTextarea : true                   

                }); 
            });
        </script>

  

 (4)新聞內容的儲存

在上一步使用了ipandao的md後,他提供了2個方法用來獲取錄入的內容:

testEditor.getMarkdown();       // 獲取 Markdown 原始碼
testEditor.getHTML();           // 獲取 Textarea 儲存的 HTML 原始碼

接下來一個問題,使用者寫好的MD以怎麼的格式儲存到MSSQL裡?

如果直接儲存HTML,那麼後期使用者將無法編輯文章,因為MD無法直接載入HTML,他識別不了HTML。

如果直接儲存MD,那麼瀏覽器並不能識別MD,這就要使用者訪問幫助文件時,每次都JS解析MD,可能使用者感覺速度會沒那麼快。

如果同時儲存HTML和MD,前端瀏覽器顯示用HTML,後臺,使用者更新時用MD,通過程式儲存資料同步,這會佔用資料庫空間。

總之,基本上沒有完美的解決方法。

在我的做法裡,是直接儲存MD原始碼,然後前端使用者訪問時,利用MD提供的markdownToHTML方法,轉換為HTML進行渲染。

我看了MSDN,猜測他應該是MD和HTML同時儲存。

 testEditor.markdownToHTML("contents");

 

(5)右邊快速預覽

右邊快速預覽其實是從MD裡提取<h3>標題實現的。

$(function () {
    editormd.markdownToHTML("contents");
    let menu = "<h5>本頁內容</h4>";
    $("#contents h3").each(
        function () {
            menu += "<a class='quick_a' href='#" + $(this).text() + "'>" + $(this).text() + "</a>";
        }
        );

    $("#rightmenu").html(menu);
    $("#rightmenu").pin({
        minWidth: 800,
        padding: { top: 50 }
    });

});

  

在上面,還是用了一個外掛:jquery.pin()。

他的作用但是:當頁面過長,往下滾動時,他會把右邊導航“釘”在右上角。

 

這樣,一個仿MSDN核心功能介紹完了,剩下的就是普通的資料庫增刪讀寫了。

本系統演示見  http://demo.dotnetcms.org/kbase 使用者名稱 admin,密碼123456

相關文章