实现一个简易版代码编辑预览功能

简易版代码编辑预览功能

前言

最近在使用掘金时候,在想有没有个离线版本的码上掘金呢?这样就能在本地很方便地调试自己的前端demo了,于是说干就干,自己动手实现一个具有代码编辑器和页面预览功能的简易版码上掘金。实现效果图如下所示:

介绍

首先,如何实现一个代码编辑器呢,还需要支持高亮显示、代码折叠、突出显示匹配的括号...等功能。当然这就不重复造轮子了,直接站在巨人的肩膀上,经过一番搜索,最终找到了github.com/ajaxorg/ace...

页面结构

一个网页最简单无非就是三个元素,html、css、js。因此直接将上半部分一分为三,下半部分负责展示预览的页面。html框架代码如下:

xml 复制代码
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Editor</title>
    <link href="static/css/ace.css" rel="stylesheet">
</head>
<body>
<div id="box">
<div id="top">
    <ul class="layout-code">
        <li>
            <div class="title">HTML代码</div>
            <div class="content">
                <pre id="editorHtml" class="editor"></pre>
            </div>
        </li>
        <li>
            <div class="title">css代码</div>
            <div class="content">
                <pre id="editorCss" class="editor"></pre>
            </div>
        </li>
        <li>
            <div class="title">javascript代码</div>
            <div class="content">
                <pre id="editorJs" class="editor"></pre>
            </div>
        </li>
    </ul>
</div>

<div class="layout-preview" id="bottom">
    <div class="title">效果预览</div>
    <div class="content">
        <iframe id="preview" frameborder="0"></iframe>
    </div>
</div>
<div id="line"></div>
</div>
<script src="static/libs/require.js"></script>
</body>
</html>

引入ACE

使用require,引入ace相关资源,设置编辑器主题以及为不同的代码类型配置代码编辑器,并初始化编辑器中的默认值,具体使用可查看 github.com/ajaxorg/ace

swift 复制代码
<script>
    require(["ace/ace", "ace/ext/code_lens"], function(ace, codeLens) {
        var option = {
            enableBasicAutocompletion: true,
            enableSnippets: true,
            enableLiveAutocompletion: false
        };
        // html
        var editorHtml = ace.edit("editorHtml");
        editorHtml.session.setMode("ace/mode/html");
        editorHtml.setTheme("ace/theme/chaos");
        editorHtml.setOptions(option);
        editorHtml.setValue("<div id='map'></div>");
        editorHtml.moveCursorTo(0, 0);
        editorHtml.session.on('change', function (e) {
            runAllCodes();
        });
        // css
        var editorCss = ace.edit("editorCss");
        editorCss.session.setMode("ace/mode/css");
        editorCss.setTheme("ace/theme/chaos");
        editorCss.setOptions(option);
        editorCss.setValue("html,\n" +
            "body,\n" +
            "#map {\n" +
            "  width: 100%;\n" +
            "  height: 100%;\n" +
            "  margin: 0;\n" +
            "  padding: 0;\n" +
            "  overflow: hidden;\n" +
            "}");
        editorCss.moveCursorTo(0, 0);
        editorCss.session.on('change', function (e) {
            runAllCodes();
        });
        // js
        var editorJs = ace.edit("editorJs");
        editorJs.session.setMode("ace/mode/javascript");
        editorJs.setTheme("ace/theme/chaos");
        editorJs.setOptions(option);
        editorJs.setValue("document.getElementById('map').innerText = 'Hello World!';");
        editorJs.moveCursorTo(0, 0);
        editorJs.session.on('change', function (e) {
            runAllCodes();
        });

        runAllCodes();

        function runAllCodes() {
            var html = editorHtml.getValue();
            var css = editorCss.getValue();
            var js = editorJs.getValue();

            var code = "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "  <meta charset=\"UTF-8\">\n" +
                "  <title>Editor</title>\n" +
                "  <style>";
            code += "\n" + css;

            code +=
                "\n  </style>\n" +
                "</head>\n" +
                "<body>\n";
            code += "\n" + html;

            code +=
                "\n  <script>\n";
            code += "\n" + js;
            code +=
                "\n  <\/script>\n" +
                "<\/body>\n" +
                "</html>";
            document.getElementById("preview").setAttribute("srcdoc", code);
        }
    })
</script>

关于预览

我们编辑的代码如何插入到当前页面中,来实现预览呢,答案是使用iframe,iframe可以通过src嵌入外部链接,但可能大部分人不知道的是使用iframe的srcdoc属性,可以嵌入一个完整的html页面代码。我们直接将html、js、css组合拼接通过document.getElementById("preview").setAttribute("srcdoc", code)来将我们自定义的代码渲染到预览窗口上。

swift 复制代码
<iframe id="preview" frameborder="0"></iframe>


 function runAllCodes() {
    var html = editorHtml.getValue();
    var css = editorCss.getValue();
    var js = editorJs.getValue();

    var code = "<!DOCTYPE html>\n" +
        "<html lang=\"en\">\n" +
        "<head>\n" +
        "  <meta charset=\"UTF-8\">\n" +
        "  <title>Editor</title>\n" +
        "  <style>";
    code += "\n" + css;

    code +=
        "\n  </style>\n" +
        "</head>\n" +
        "<body>\n";
    code += "\n" + html;

    code +=
        "\n  <script>\n";
    code += "\n" + js;
    code +=
        "\n  <\/script>\n" +
        "<\/body>\n" +
        "</html>";
    document.getElementById("preview").setAttribute("srcdoc", code);
    }
        

改变页面上下布局

为方便改变编辑代码框和预览页面的大小占比,需要制作一个可拖拽来改变窗口大小的功能,通过监听鼠标按下、移动事件来动态改变上下两个模块的高度,具体实现方法如下:

ini 复制代码
<script>
    function $(id) {
        return document.getElementById(id);
    }
    window.onload = function() {
        var oBox = $("box"), oTop = $("top"), oBottom = $("bottom"), oLine = $("line");
        //鼠标按下移动时动态改变各个窗口的高度
        oLine.onmousedown = function(e) {
            var disY = (e || event).clientY;
            oLine.top = oLine.offsetTop;

            document.onmousemove = function(e) {
                var iT = oLine.top + ((e || event).clientY - disY);
                var e=e||window.event,tarnameb=e.target||e.srcElement;
                var maxT = oBox.clientHeight - oLine.clientHeight;
                oLine.style.margin = 0;
                iT < 0 && (iT = 0);
                iT > maxT && (iT = maxT);
                oLine.style.top = oTop.style.height = iT + "px";
                oBottom.style.height = oBox.clientHeight - iT + "px";
                //$("msg").innerText='top.width:'+oLine.style.height+'---bottom.height:'+oBottom.style.height+'---oLine.offsetHeight:'+oLine.offsetHeight+'---disY:'+disY+'---tarnameb:'+tarnameb.tagName;
                return false
            };
            //鼠标收起清空事件
            document.onmouseup = function() {
                document.onmousemove = null;
                document.onmouseup = null;
                oLine.releaseCapture && oLine.releaseCapture()
            };
            oLine.setCapture && oLine.setCapture();
            return false
        };
    };
</script>

以上便是实现一个简易版码上掘金的方法和思路,具体源码可查看:gitee.com/fcli/my-cod... 运行依赖node环境,可通过nginx代理使用。

总结

通过以上操作就能实现一个简易版码上掘金,文中涉及的ACE相关知识可到github.com/ajaxorg/ace 查看相关使用和配置。当然真正的在线代码编辑器比这复杂的多,如果觉得有用欢迎大家点赞加关注哦。

相关推荐
CRPER11 分钟前
告别繁琐配置:一个现代化的 TypeScript 库开发模板,让你高效启动项目!
前端·typescript·node.js
Embrace23 分钟前
NextAuth实现Google登录报错问题
前端
小海编码日记26 分钟前
Geadle,Gradle插件,Android Studio and sdk版本对应关系
前端
粤M温同学30 分钟前
Web前端基础之HTML
前端·html
love530love36 分钟前
是否需要预先安装 CUDA Toolkit?——按使用场景分级推荐及进阶说明
linux·运维·前端·人工智能·windows·后端·nlp
泯泷2 小时前
「译」为 Rust 及所有语言优化 WebAssembly
前端·后端·rust
LinXunFeng2 小时前
Flutter - GetX Helper 如何应用于旧页面
前端·flutter·开源
紫薯馍馍2 小时前
Dify创建 echarts图表 (二)dify+python后端flask实现
前端·flask·echarts·dify
梦想很大很大2 小时前
把业务逻辑写进数据库中:老办法的新思路(以 PostgreSQL 为例)
前端·后端·架构
李三岁_foucsli2 小时前
从生成器和协程的角度详解async和await,图文解析
前端·javascript