修改大佬的代码,原来是可以修改参数的,我这边要求不能手动修改参数 

增加删除功能,自定义添加参数,

反向解析公式没整好,有大佬会的,可以修改一下,联系一下我,不胜感激

原文  用vue手写一个公式组件 - SegmentFault 思否

后来进行了改进 功能进行了简化 ,可详见vue公式编辑器 加强版(简化版)_你好,我叫A某人的博客-CSDN博客_vue公式编辑器

<template>
    <div id="formulaPage">
        <h1>formulaPage</h1>
        <p>{{ formulaStr }}</p>
        <div class="btnGroup">
            <!-- <button @click="mouseRange($event)">获取光标</button> -->
            <button @click="getFormula">获取公式</button>
            <button
                @click="
                    parsingFormula(
                        '#字段1#+plus(#字段1#+#字段3#)*abs(#字段4#/#字段2#)'
                    )
                "
            >
                反向解析公式
            </button>
        </div>
        <!-- <div class="tab">
            <div class="tit">添加公式</div>
            <ul>
                <li @click="addItem($event, 2)">plus()</li>
                <li @click="addItem($event, 2)">abs()</li>
            </ul>
        </div> -->
        <div class="tab">
            <div class="tit">添加字段</div>
            <ul>
                <li @click="addItem($event, 1)">字段1</li>
                <li @click="addItem($event, 1)">字段2</li>
                <li @click="addItem($event, 1)">字段3</li>
                <li @click="addItem($event, 1)">字段4</li>
            </ul>
        </div>
        <div class="tab">
            <div class="tit">数字</div>
            <ul>
                <li @click="addItem($event, 3)">1</li>
                <li @click="addItem($event, 3)">2</li>
                <li @click="addItem($event, 3)">3</li>
                <li @click="addItem($event, 3)">4</li>
                <li @click="addItem($event, 3)">5</li>
                <li @click="addItem($event, 3)">6</li>
                <li @click="addItem($event, 3)">7</li>
                <li @click="addItem($event, 3)">8</li>
                <li @click="addItem($event, 3)">9</li>
                <li @click="addItem($event, 3)">0</li>
            </ul>
        </div>
        <div class="tab">
            <div class="tit">数学运算符</div>
            <ul>
                <li @click="addItem($event, 3)">+</li>
                <li @click="addItem($event, 3)">-</li>
                <li @click="addItem($event, 3)">*</li>
                <li @click="addItem($event, 3)">/</li>
                <li @click="addItem($event, 3)">(</li>
                <li @click="addItem($event, 3)">)</li>

                <li @click="remove()">del</li>
            </ul>
        </div>
        <!-- 公式编辑区域 -->
        <div
            class="formulaView"
            id="formulaView"
            ref="formulaView"
            @click="recordPosition"
            @keyup="editEnter($event)"
            @copy="copy($event)"
            @paste="paste($event)"
            contentEditable="false "
        ></div>
    </div>
</template>
<script>
export default {
    name: "formulaPage",
    data: function () {
        return {
            // 公式字符串
            formulaStr: "",
            // 公式编辑器最后光标位置
            formulaLastRange: null,
        };
    },
    methods: {
        // 获取公式
        getFormula: function () {
            var nodes = this.$refs.formulaView.childNodes;
            var str = "";
            for (let i = 0; i < nodes.length; i++) {
                var el = nodes[i];
                if (el.nodeName == "SPAN") {
                    // console.log(el);
                    str += "#" + el.innerHTML.trim() + "#";
                } else if (el.nodeName == "B") {
                    // console.log(el);
                    str += el.innerHTML.trim() ;
                }else {
                    // console.log(el.data);
                    str += el.data ? el.data.trim() : "";
                }
            }
            // console.log(str);
            this.formulaStr = str;
        },
        // 点选时记录光标位置
        recordPosition: function () {
            // 保存最后光标点
            this.formulaLastRange = window.getSelection().getRangeAt(0);
        },
        // 添加字段 type 1 字段  2 公式 3 数字或者数字运算符
        addItem: function (e, type) {
            // 当前元素所有子节点
            var nodes = this.$refs.formulaView.childNodes;
            // 当前子元素偏移量
            var offset =
                this.formulaLastRange && this.formulaLastRange.startOffset;
            // 当前光标后的元素
            var nextEl =
                this.formulaLastRange && this.formulaLastRange.endContainer;

            // 创建节点片段
            var fd = document.createDocumentFragment();

            // 创建字段节点  空白间隔节点  公式节点
            var spanEl = document.createElement("span");
            spanEl.setAttribute("contentEditable", false);
            // 标识为新添加元素 用于定位光标
            spanEl.setAttribute("new-el", true);
            spanEl.innerHTML = e.target.innerHTML;

            var spanEl2 = document.createElement("b");
            // 标识为新添加元素 用于定位光标
            spanEl2.setAttribute("new-el", true);
            spanEl2.innerHTML = e.target.innerHTML;

            var empty = document.createTextNode(" ");
            var formulaEl = document.createTextNode(
                " " + e.target.innerHTML + " "
            );

            // 区分文本节点替换 还是父节点插入
            if (nextEl && nextEl.className != "formulaView") {
                // 获取文本节点内容
                var content = nextEl.data;

                // 添加前段文本
                fd.appendChild(
                    document.createTextNode(content.substr(0, offset) + " ")
                );
                fd.appendChild(type == 1 ? spanEl : formulaEl);
                // 添加后段文本
                fd.appendChild(
                    document.createTextNode(" " + content.substr(offset))
                );
                // 替换节点
                this.$refs.formulaView.replaceChild(fd, nextEl);
                // 添加前段文本
                // fd.appendChild(empty);
                // fd.appendChild(type == 1 ? spanEl : spanEl2);
                // fd.appendChild(empty);

                // // 如果有偏移元素且不是最后节点  中间插入节点  最后添加节点
                // if (nodes.length && nodes.length > offset) {
                //     this.$refs.formulaView.insertBefore(
                //         fd,
                //         nextEl && nextEl.className != "formulaView"
                //             ? nextEl
                //             : nodes[offset]
                //     );
                // } else {
                //     this.$refs.formulaView.appendChild(fd);
                // }
            } else {
                // 添加前段文本
                fd.appendChild(empty);
                fd.appendChild(type == 1 ? spanEl : spanEl2);
                fd.appendChild(empty);

                // 如果有偏移元素且不是最后节点  中间插入节点  最后添加节点
                if (nodes.length && nodes.length > offset) {
                    this.$refs.formulaView.insertBefore(
                        fd,
                        nextEl && nextEl.className != "formulaView"
                            ? nextEl
                            : nodes[offset]
                    );
                } else {
                    this.$refs.formulaView.appendChild(fd);
                }
            }

            // 遍历光标偏移数据 删除标志
            var elOffSet = 0;
            for (let i = 0; i < nodes.length; i++) {
                let el = nodes[i];
                // console.log(el,el.nodeName == 'SPAN'&&el.getAttribute('new-el'));
                if (el.nodeName == "SPAN" && el.getAttribute("new-el")) {
                    elOffSet = i;
                    el.removeAttribute("new-el");
                }
                if (el.nodeName == "B" && el.getAttribute("new-el")) {
                    elOffSet = i;
                    el.removeAttribute("new-el");
                }
            }

            // 创建新的光标对象
            var range = document.createRange();
            // 光标对象的范围界定
            range.selectNodeContents(
                type == 1 ? this.$refs.formulaView : formulaEl
            );
            // 光标位置定位
            range.setStart(
                type == 1
                    ? this.$refs.formulaView
                    : type == 2
                    ? formulaEl
                    : formulaEl,
                type == 1
                    ? elOffSet + 1
                    : type == 2
                    ? formulaEl.data.length - 2
                    : formulaEl.data.length - 1
            );

            // 使光标开始和光标结束重叠
            range.collapse(true);
            // 清除选定对象的所有光标对象
            window.getSelection().removeAllRanges();
            // 插入新的光标对象
            window.getSelection().addRange(range);

            // 保存新光标
            // this.recordPosition();
        },
        remove() {
            var formulaView = document.getElementById("formulaView");
            console.log(formulaView);
            formulaView.removeChild(formulaView.lastElementChild);
        },
        // 复制
        copy: function (e) {
            // 选中复制内容
            e.preventDefault();
            //
            var selContent = document.getSelection().toString().split("\n")[0];
            // 替换选中内容
            e.clipboardData.setData("text/plain", selContent);
        },
        // 输入回车
        editEnter: function (e) {
            // console.log(e);
            e.preventDefault();

            // return '<br/>';
            // return
            if (e.keyCode == 13) {
                // 获取标签内容 并把多个换行替换成1个
                var content = this.$refs.formulaView.innerHTML.replace(
                    /(<div><br><\/div>){2,2}/g,
                    "<div><br></div>"
                );

                // debugger;

                // 记录是否第一行回车
                var divCount = this.$refs.formulaView.querySelectorAll("div");
                // var tE = this.$refs.formulaView.querySelect('div');
                // console.log(this.$refs.formulaView.childNodes);
                // console.log(this.$refs.formulaView.querySelectorAll("div"));
                // 获取当前元素内所有子节点
                var childNodes = this.$refs.formulaView.childNodes;
                // 记录当前光标子节点位置
                var rangeIndex = 0;
                for (let i = 0; i < childNodes.length; i++) {
                    var one = childNodes[i];
                    if (one.nodeName == "DIV") {
                        rangeIndex = i;
                    }
                }
                // console.log(rangeIndex);
                // debugger;
                // console.log(content);

                // 如果有替换则进行光标复位
                if (divCount.length >= 1) {
                    // 替换回车插入的div标签
                    content = content.replace(
                        /<div>|<\/div>/g,
                        function (word) {
                            // console.log(word);
                            if (word == "<div>") {
                                // 如果是第一行不在替换br
                                return divCount.length > 1 ? " " : " <br>";
                            } else if (word == "</div>") {
                                return " ";
                            }
                        }
                    );
                    // 更新替换内容,光标复位
                    this.$refs.formulaView.innerHTML = content;
                    // 创建新的光标对象
                    var range = document.createRange();
                    // 光标对象的范围界定为新建的表情节点
                    range.selectNodeContents(this.$refs.formulaView);
                    // 光标位置定位在表情节点的最大长度
                    range.setStart(
                        this.$refs.formulaView,
                        rangeIndex + (divCount.length > 1 ? 0 : 1)
                    );
                    // 使光标开始和光标结束重叠
                    range.collapse(true);
                    // 清除选定对象的所有光标对象
                    window.getSelection().removeAllRanges();
                    // 插入新的光标对象
                    window.getSelection().addRange(range);
                }
            }
            // 保存最后光标点
            this.formulaLastRange = window.getSelection().getRangeAt(0);
        },
        // 获取粘贴事件
        paste: function (e) {
            e.preventDefault();
            // var txt=e.clipboardData.getData();
            // console.log(e, e.clipboardData.getData());
            return "";
        },
        // 公式反向解析
        parsingFormula: function (formulaStr) {
            // 渲染视口
            var view = this.$refs.formulaView;
            // 反向解析公式
            var str = formulaStr.replace(/#(.+?)#/g, function (word, $1) {
                // console.log(word,$1);
                return "<span contentEditable='false'>" + $1 + "</span>";
            });

            // console.log(str,fd.innerHTML);
            view.innerHTML = str;
            // this.$refs.formulaView.appendChild(fd);

            // 创建新的光标对象
            var range = document.createRange();
            // 光标对象的范围界定为新建的表情节点
            range.selectNodeContents(view);
            // 光标位置定位在表情节点的最大长度
            range.setStart(view, view.childNodes.length);

            // 使光标开始和光标结束重叠
            range.collapse(true);
            // 清除选定对象的所有光标对象
            window.getSelection().removeAllRanges();
            // 插入新的光标对象
            window.getSelection().addRange(range);

            // 保存新光标
            // this.recordPosition();
        },
    },
};
</script>
<style lang="less">
#formulaPage {
    > .tab {
        > ul {
            &:after {
                content: "";
                display: table;
                clear: both;
            }
            > li {
                margin-right: 20px;
                float: left;
                padding: 0 10px;
                height: 25px;
                line-height: 25px;
                border-radius: 5px;
                border: 1px solid #000;
            }
        }
    }
    > .formulaView {
        margin-top: 20px;
        min-height: 100px;
        width: 300px;
        padding: 5px;
        border: 2px solid #000;
        resize: both;
        overflow: auto;
        line-height: 25px;
        span {
            user-select: none;
            display: inline-block;
            margin: 0 3px;
            height: 20px;
            line-height: 20px;
            letter-spacing: 2px;
            background: #aaa;
            border-radius: 3px;
            white-space: nowrap;
            color: red;
            &:first-child {
                margin-left: 0;
            }
        }
    }
}
</style>

Logo

前往低代码交流专区

更多推荐