首页 > 网站 > WEB开发 > 正文

自己动手制作更好用的markdown编辑器-01

2024-04-27 14:10:29
字体:
来源:转载
供稿:网友

自己动手制作更好用的markdown编辑器-01

这里文章都是从个人的github博客直接复制过来的,排版可能有点乱. 原始地址 http://benq.im文章目录
  1. 1. 简介
  2. 2. 项目结构
  3. 3. 程序主界面
  4. 4. 拖动窗口
  5. 5. app.js
  6. 6. 导航栏按钮
  7. 7. 实现简单的markdown编辑器
    1. 7.1. 定义路由
    2. 7.2. 实现controller
    3. 7.3. 添加视图模版
    4. 7.4. 实现editor
    5. 7.5. 实现directive
    6. 7.6. 最终效果
  8. 8. 总结
  9. 9. 附件

前段时间用hexo重新搭了个人博客,顺便写了个简单的博客搭建教程.

用markdown写起博客流畅很多,但是用了几个markdown编辑器,都没有一个适合自己使用的。于是就想自己动手做一个,当然不是完全从0开始做,语法高亮和markdown解析都用的是开源的项目.从这篇开始,我会把整个开发过程记录成系列随笔,因此开发进度较为缓慢.

博客写得少,像这样写长一点的随笔就有点混乱,看不懂的请用力喷,我会努力改进.

简介

先介绍下开发过程中用到的一些比较重要的开源项目:

  1. nw.js,原名node-webkit,用webkit和node来做基于web技术的跨平台客户端软件.
  2. CodeMirror,基于web技术实现的文本编辑器,实现了大部分的IDE功能以及几乎全部你会用到的语言的支持.目前我日常开发都是用这个IDE,甚至在做hexomd这个项目时用的IDE也是CodeMirror做的.
  3. angularjs,google的mvvm开发框架,这个相信不用我多做介绍.我用的不熟,觉得好用就拿来即用,没有深入的了解过.

关于这些开源项目的使用,我在这系列文章里不会详细解释,如果有疑问,可以去看官网的入门教程和wiki,当然也欢迎讨论.

项目结构

图片里的是我目前的项目结构,大概讲解一下一些目录和文件的用途。

  1. icudtl.dat,nw.exe,nw.pak这3个是nw.js在windows运行所必须的文件.

  2. package.jsonnw.js的配置文件

    1234567891011121314151617181920212223
    {  "name": "HexoMD",  "description": "Markdown for hexo",  "main": "app/index.html",//程序入口页面  "author": "hmjlr123@Gmail.com",  "license": "MIT",  "directories": {    "test": "no"  },  "devDependencies": {},  //窗口配置  "window": {    "title": "HexoMD",    "icon": "app/img/logo.png", //logo    "toolbar": true, //是否显示地址栏工具条(调试的时候启用)    "frame": false, //是否显示程序边框    "width": 1000, //默认宽度    "height": 700, //默认高度    "position": "center", //启动时在屏幕中的位置    "min_width": 600, //最小宽度    "min_height": 400 //最小高度  }}
  3. app目录程序的所有源代码的根目录.

  4. app/lib存放angular,jquery,codemirror等开源库/框架的源代码

  5. app/helpers存放一些node的工具函数

  6. app/modules程序代码在这个目录,按功能模块分成不同的子目录.modules/app.js是整个程序的入口点

  7. app/package.jsonnode模块配置,注意与上层的package.json意义不同

  8. app/index.html程序的主界面窗口

程序主界面

index.html

123456789101112131415161718192021222324252627282930
<!DOCTYPE html><html lang="en"><head>  <meta charset="utf-8">  <title>Hexo Markdown</title>  <link href="CSS/bootstrap.css" rel="stylesheet">  <link href="lib/codemirror/lib/codemirror.css" rel="stylesheet" />  <link href="css/index.css" rel="stylesheet"></head><body>  <!--导航栏-->  <nav class="navbar navbar-inverse navbar-fixed-top">   省略...  </nav>  <!--模块视图区域-->  <article class="container app" ui-view ng-animate="'view'"></article>  <!--工具栏-->  <footer class="tool"></footer>  <!--end codemirror-->  <script src="lib/jquery-2.1.3.js"></script>  <script src="lib/angular.js"></script>  <script src="lib/angular-ui-router.js"></script>  <!--程序入口函数-->  <script src="modules/app.js"></script>  <script>    //初始化angular,hmd为自定义的根模块名    angular.bootstrap($('body'), ['hmd']);</script></body></html>

只贴出部分代码.以后的所有代码也类似,都只会把重要的贴出来,并给出完整的链接.

界面采用比较简洁的三栏布局,分别为导航栏内容区状态栏/工具条.最顶部的地址栏只有在开发的时候为了方便调试才开启,发布时会关闭掉.

拖动窗口

为了美观,我们在配置里去掉了系统自带的边框.因此要实现自定义的拖动窗口功能还需要增加一些设置.所谓的设置,其实只要加上对应的样式即可,功能都由nw.js实现了.

123
.navbar{  -webkit-app-region: drag;}

带有此样式的元素可以作为窗口的拖拽区域,并且双击时最大化/还原窗口.

123
.navbar .navbar-collapse a {    -webkit-app-region: no-drag;}

被标志为可drag的容器里的链接将不可点击,因此要特别为链接加上no-drag

另外为了让程序看起来更像客户端一点,我默认禁用掉了文本选择,防止一些被作为按钮的a标签的文本被选中

1234
html {    height: 100%;    -webkit-user-select: none;}

app.js

app.js作为程序的入口点,定义了整个项目代码的结构,需要特别拿出来说明一下.

1
angular.module('hmd', ['ui.router','hmd.studio'])

定义angular模块,modules所有的业务模块都会放到单独的子目录里,如这里注册的hmd.studio

123456789101112131415
//模块根目录var baseModuleDir = './app/modules/'; //引入模块,模块内js文件会被自动加载到页面中 hmd.regModule = function (name, reqModule) {   hmd[name] = angular.module('hmd.' + name, reqModule || []);   hmd[name].moduleName = name;   //模块存储数据的目录   hmd[name].dataPath = hmd.storeDir + '//' + hmd[name].moduleName;   fs.readdirSync(baseModuleDir + name)   .forEach(function (file) {     if (~file.indexOf('.js')) {       document.write('<script src="modules/' + name + '/' + file + '"></script>');     }   }); };

regModule方法实现最简单的模块载入,自动加载模块内的所有脚本到页面中,并为每个模块赋予一个单独的数据存储目录dataPath

1
hmd.storeDir =  require('nw.gui').App.dataPath;

程序的数据存储目录

导航栏按钮

导航栏右边有4个按钮,分别为:检查更新最小化最大化关闭

12345678910
...<!--导航栏功能按钮--><div class="btn-group window-tool">  <a class="btn rectbtn" href="javascript://" title="点击检查更新">  <i class="glyphicon  mdfi_action_system_update_tv"></i></a>  <a class="btn rectbtn" href="Javascript://"><i class="glyphicon glyphicon-minus"></i></a>  <a class="btn rectbtn" href="javascript://"><i class="glyphicon glyphicon-fullscreen"></i></a>  <a class="btn rectbtn" href="javascript://"><i class="glyphicon glyphicon-remove"></i></a></div>...

检查更新等以后再实现.现在先实现后面3个功能因为这3个功能是全局的,因此在modules根目录新建directives.js用于实现全局的Directive.

1234567891011121314151617181920212223242526272829303132333435363738394041424344
(function () {  var gui = require('nw.gui'), win = gui.Window.get(),winMaximize = false;  angular.module('hmd.directives', [])  //最小化窗口  .directive('hmdMinisize', [function () {    return function (scope, elem) {      $(elem[0]).on('click', function () {        win.minimize();      });    };  }])  //最大化与还原窗口  .directive('hmdMaxToggle', [function () {    return function (scope, elem) {      //窗口最大化和还原时会触发对应的事件,在事件里去控制按钮样式.      //TODO:这里的实现应该可以优化得更优雅一点,以后再说      win.on('maximize', function () {        winMaximize = true;        $(elem[0]).find('i').removeClass('glyphicon-fullscreen').addClass('glyphicon-resize-small');      });      win.on('unmaximize', function () {        winMaximize = false;        $(elem[0]).find('i').removeClass('glyphicon-resize-small').addClass('glyphicon-fullscreen');      });//切换窗口状态      $(elem[0]).on('click
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表