zoukankan      html  css  js  c++  java
  • 自己动手制作更好用的markdown编辑器-03

    这里文章都是从个人的github博客直接复制过来的,排版可能有点乱. 原始地址 http://benq.im/2015/04/24/hexomd-03/
    文章目录
    1. 1. 系统模块
    2. 2. 记录上次打开的文件
    3. 3. 编辑器样式选择
      1. 3.1. 样式修改表单
      2. 3.2. 自动生成select列表
    4. 4. 总结
    5. 5. 附件

    上一篇我们实现了文件的新建,保存,打开功能.

    在这篇里我们将实现以下功能:

    1. 系统模块,包含一些软件的设置和存储功能
    2. 记录上次打开的文件
    3. 编辑器样式选择

    系统模块

    跟之前的studio模块类似,我们在modules模块下增加system目录.

    比studio多了model.js文件,用来实现系统模块的一些功能.

    app.js里加载system模块

    1
    2
    3
    4
    5
    6
    angular.module('hmd', ['ui.router','hmd.directives','hmd.studio','hmd.system'])
    ...
    //引入模块
    hmd.regModule('studio');
    hmd.regModule('system');
    ...

    路由、导航栏
    angular.js用得不熟,导航栏的状态根据route来切换一直不知道怎么实现比较优雅.
    我直接在app.js里增加了一个导航栏切换的方法,每个route的onEnter事件里自行调用这个方法.

    1
    2
    3
    4
    5
    6
    //TODO:更优雅的导航栏切换逻辑
    hmd.changeStatus = function (state) {
    var $navList = $('#navlist');
    $navList.find('li').removeClass('active');
    $navList.find('.' + state).addClass('active');
    };

    system/route.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    hmd.system.config(function ($stateProvider, $urlRouterProvider) {
    $stateProvider
    .state('system', {
    url: "/system",
    templateUrl: "modules/system/views/system.html",
    controller: 'system',
    onEnter: function () {
    hmd.changeStatus('system');
    }
    });
    });

    studio/route.js

    1
    2
    3
    4
    5
    ...
    onEnter: function () {
    hmd.changeStatus('studio')
    ;

    }
    ...

    然后在index.html里配置好导航

    1
    2
    3
    4
    5
    6
    ...
    <ul class="nav navbar-nav" id="navlist" >
    <li class="studio"><a href="#/studio">编辑器</a></li>
    <li class="system"><a href="#/system">系统设置</a></li>
    </ul>
    ...

    导航栏最终效果:

    记录上次打开的文件

    每次打开文件都会被记住,下次重新启动程序时将默认打开最后一次打开的文件.

    system设置的读取和保存

    我们先在system/model.js实现保存和读取设置的功能.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    var util = require('./helpers/util'),
    fs = require('fs'),
    system = hmd.system,
    //存储设置的文件
    dataFile = system.dataPath + '\system.json';

    //初始化存储目录
    if (!fs.existsSync(system.dataPath)) {
    fs.mkdirSync(system.dataPath);
    }

    //默认设置
    var defaultSystemData = {
    //最后一次打开的文件
    lastFile: null
    };

    //读取设置
    system.get = function () {
    return $.extend(defaultSystemData,util.readJsonSync(dataFile));
    };

    //保存设置
    system.save = function (data) {
    data = data || defaultSystemData;
    util.writeFileSync(dataFile, JSON.stringify(data));
    };

    //设置最后打开的文件
    system.setLastFile = function (filepath) {
    var systemData = system.get();
    systemData.lastFile = filepath;
    system.save(systemData);
    };

    system实现了getsave方法,所有的设置都存储在一个简单的对象里,代码里并没有对这个对象做缓存,每次都是从文件里读取,因为这简单的文件还远达不到影响读取速度的情况.

    然后我们修改editorsetFile方法,暴露setFiled事件给外部使用.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //设置当前文件
    setFile:function(filepath){
    if(filepath && fs.existsSync(filepath)){
    var txt = util.readFileSync(filepath);
    this.filepath = filepath;
    this.cm.setValue(txt);
    this.fire('setFiled',this.filepath);
    }
    else{
    this.filepath = null;
    this.cm.setValue('');
    this.fire('setFiled');
    }
    }

    最后修改studio/directives.jshmdEditor,实现这个功能.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    studio.directive('hmdEditor', function () {
    return function ($scope, elem) {
    //读取最后一次打开的文件
    var systemData = hmd.system.get();
    hmd.editor.init({el:elem[0]},systemData.lastFile);
    //保存最后一次打开的文件
    hmd.editor.on('setFiled',function(filepath){
    hmd.system.setLastFile(filepath);
    });
    ...

    编辑器样式选择

    样式修改表单

    样式文件在目录app/lib/codemirror/theme.
    目录里每一个样式文件代表一种编辑器样式,还记得当初实现editorinit时,样式已经是通过配置传入的.

    1
    2
    3
    4
    5
    ...
    if(options.theme != 'default'){
    $('head').append('<link href="lib/codemirror/theme/'+options.theme+'.css" rel="stylesheet" />');
    }
    ...

    现在我们只要把theme参数存储到配置里,并提供给用户修改就可以.

    system/model.js里的默认配置增加一个theme字段.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ...
    //默认设置
    var defaultSystemData = {
    //最后一次打开的文件
    lastFile: null,
    //当前样式
    theme:'ambiance'
    };
    ...

    修改system/views/system.html模版,增加样式表单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <div class="content studio-wrap">
    <form class="system-form" name="systemForm">
    <div class="form-group">
    <label>编辑器样式</label>
    <select ng-model="systemSetting.theme" name="theme">
    <option value="ambiance">ambiance</option>
    <option value="mbo">mbo</option>
    <option value="neat">neat</option>
    </select>
    </div>
    <button type="submit" class="btn btn-default" ng-click="save(systemSetting)">保存</button>
    </form>
    </div>

    这里的select控件我们先写了3个选项.现在先实现这个修改样式的功能,等完成这个功能后再把选项列表做成自动生成.

    对应的system/controllers.js(开发了3天了,终于第一次用到controller了)

    1
    2
    3
    4
    5
    6
    system.controller('system', function ($scope) {
    $scope.systemSetting = system.get();
    $scope.save = function (systemSetting) {
    system.save(systemSetting);
    };
    });

    controller里读取system的数据,并赋值给$scope.systemSetting,用于表单的数据绑定.由于angular实现了数据的双向绑定,因此用户编辑表单时,绑定的数据也会跟着更新.这样我们的save方法里只要将表单绑定的数据保存回system即可.

    button按钮绑定save方法ng-click="save(systemSetting)".

    这里可以稍微感受到angular让我们节省了很多工作量.

    自动生成select列表

    修改controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var system = hmd.system,
    fs = require('fs');
    system.controller('system', function ($scope) {
    //读取theme目录,生成样式列表
    var files = fs.readdirSync('./app/lib/codemirror/theme'),themes={};
    files.forEach(function (file) {
    if(~file.indexOf('.css')){
    file = file.replace('.css','');
    themes[file] = file;
    }
    });
    $scope.themes = themes;
    $scope.systemSetting = system.get();
    $scope.save = function (systemSetting) {
    system.save(systemSetting);
    };
    });

    theme目录里读取所有样式列表,生成键值对,然后赋值给$scope.themes

    修改视图模版:

    1
    2
    <select name="theme" ng-model="systemSetting.theme"  ng-options="k as v for (k, v) in themes">
    </select>

    ng-options="k as v for (k, v) in themes"是angular的绑定语法

    这样我们就实现了样式列表的自动读取,用户如果想自定义样式,只要在app/lib/codemirror/theme目录新增一个样式文件,并写上自己的样式就可以在系统设置里选择自定义的样式了.

    总结

    今天实现了记忆最后一次打开的文件以及样式选择的功能,并且第一次使用了angularcontroller,感受到了angular双向数据绑定的强大.

    我们的程序又更好用一些了(但是随着界面变多,又更丑了,太为难了).

    最终效果截图

    附件

    本篇程序打包
    项目地址

  • 相关阅读:
    nginx
    同步和异步
    什么是ACID
    关系型数据库特点小结
    js 简单小知识
    join 和 left join 和 right join的区别?
    mysql中having和where区别?
    include和require区别
    什么是脏读,不可重复,幻读?
    Mysql常见面试题
  • 原文地址:https://www.cnblogs.com/honghongming/p/4453982.html
Copyright © 2011-2022 走看看