简易的JS计算器实现代码


Posted in Javascript onOctober 18, 2016

看看手机中的计算器,分为普通计算器和科学计算器

简易的JS计算器实现代码

 自认脑袋不够大,就实现一个普通版本的吧(支持正负数加减乘除等基本连续的运算,未提供括号功能)

看看图示效果:

简易的JS计算器实现代码

一、知识准备

1+1 = ?

正常来说,我们看到这个表达式都知道怎么运算,知道运算结果

但计算机不一样,计算机无法识别出这串表达式,它只能识别特定的规则:前缀表达式+ 1 1 或后缀表达式1 1 +

举个栗子

(3 + 4) × 5 - 6 就是中缀表达式
- × + 3 4 5 6 前缀表达式
3 4 + 5 × 6 - 后缀表达式 

所以为了实现程序的自动运算,我们需要将输入的数据转化为前缀或后缀表达式

前缀、中缀、后缀表达式的概念以及相互转换方法在这里就不多说了,这篇博文 说得比较清楚了

所以,在这个计算器的实现中,采用了后缀表达式的实现方式,参考以上文章,重点关注这两个算法:

与转换为前缀表达式相似,遵循以下步骤:
(1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入S2;
(4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
(4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
(4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
(5) 遇到括号时:
(5-1) 如果是左括号“(”,则直接压入S1;
(5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将S1中剩余的运算符依次弹出并压入S2;
(8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。

与前缀表达式类似,只是顺序是从左至右:
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
例如后缀表达式“3 4 + 5 × 6 -”:
(1) 从左至右扫描,将3和4压入堆栈;
(2) 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3) 将5入栈;
(4) 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
(5) 将6入栈;
(6) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

二、实现过程

第一步当然是搭建计算器的页面结构,不是科学计算器,只提供了基本的运算功能,但也能即时地进行运算,显示出完整的中缀表达式,运算后保存上一条运算记录。

要先说一下:本来想实现小数点功能的,但小数点的存在让数据存储与数据显示的实现有了压力,实现过程实在脑大,索性先取消这个功能。 

1. 页面结构:

<h5>计算计算</h5>
  <!-- 计算器 -->
  <div class="calc-wrap">
    <div class="calc-in-out">
      <!-- 上一条运算记录 -->
      <p class="calc-history" title=""></p>
      <!-- 输入的数据 -->
      <p class="calc-in"></p>
      <!-- 输出的运算结果 -->
      <p class="calc-out active"></p>
    </div>
    <table class="calc-operation">
      <thead></thead>
      <tbody>
        <tr>
          <td data-ac="cls" class="cls">C</td>
          <td data-ac="del">←</td>
          <td data-ac="sq">x<sup>2</sup></td>
          <td data-ac="mul">×</td>
        </tr>
        <tr>
          <td data-val="7">7</td>
          <td data-val="8">8</td>
          <td data-val="9">9</td>
          <td data-ac="div">÷</td>
        </tr>
        <tr>
          <td data-val="4">4</td>
          <td data-val="5">5</td>
          <td data-val="6">6</td>
          <td data-ac="plus">+</td>
        </tr>
        <tr>
          <td data-val="1">1</td>
          <td data-val="2">2</td>
          <td data-val="3">3</td>
          <td data-ac="minus">-</td>
        </tr>
          <td data-ac="per">%</td>
          <td data-val="0">0</td>
          <td data-ac="dot">.</td>
          <td data-ac="eq" class="eq">=</td>
      </tbody>
    </table>
  </div>

2. 结合一点样式:

body {
  padding: 20px;
  font-family: Arial;
}

.calc-wrap {
  width: 300px;
  border: 1px solid #ddd;
  border-radius: 3px;
}


.calc-operation {
  width: 100%;
  border-collapse: collapse;
}

.calc-in-out {
  width: 100%;
  padding: 10px 20px;
  text-align: right;
  box-sizing: border-box;
  background-color: rgba(250, 250, 250, .9);
}
.calc-in-out p {
  overflow: hidden;
  margin: 5px;
  width: 100%;
}
.calc-history {
  margin-left: -20px;
  font-size: 18px;
  color: #bbb;
  border-bottom: 1px dotted #ddf;
  min-height: 23px;
}

.calc-in,
.calc-out {
  font-size: 20px;
  color: #888;
  line-height: 39px;
  min-height: 39px;
}

.calc-in {
  color: #888;
}
.calc-out {
  color: #ccc;
}

.calc-in.active,
.calc-out.active {
  font-size: 34px;
  color: #666;
}

.calc-operation td {
  padding: 10px;
  width: 25%;
  text-align: center;
  border: 1px solid #ddd;
  font-size: 26px;
  color: #888;
  cursor: pointer;
}

.calc-operation td:active {
  background-color: #ddd;
}

.calc-operation .cls {
  color: #ee8956;
}

这样静态的计算器就粗来了~~

 简易的JS计算器实现代码

3. JS逻辑

这部分就是重点了,一步步来说

首先是对计算器的监听吧,也就是这个表格,可以使用事件委托的方式,在父级节点上监听处理

// 绑定事件
    bindEvent: function() {
      var that = this;

      that.$operation.on('click', function(e) {
        e = e || window.event;
        var elem = e.target || e.srcElement,
          val,
          action;

        if (elem.tagName === 'TD') {
          val = elem.getAttribute('data-val') || elem.getAttribute('data-ac');

监听数据,获取到的只是页面上的某个值/操作符,所以需要将数据存储起来形成中缀,再由中缀转换成后缀,最后通过后缀进行计算

// 中缀表达式
    this.infix = [];
    // 后缀表达式
    this.suffix = [];
    // 后缀表达式运算结果集
    this.result = [];

按照算法步骤,实现出来,这里没有使用到括号,如果实际需要,可在相应位置修改判断条件即可~

// 中缀表达式转后缀
    infix2Suffix: function() {
      var temp = [];
      this.suffix = [];

      for (var i = 0; i < this.infix.length; i++) {
        // 数值,直接压入
        if (!this.isOp(this.infix[i])) {
          this.suffix.push(this.infix[i]);
        }
        else {
          if (!temp.length) {
            temp.push(this.infix[i]);
          }
          else {
            var opTop = temp[temp.length - 1];
            // 循环判断运算符优先级,将运算符较高的压入后缀表达式
            if (!this.priorHigher(opTop, this.infix[i])) {
              while (temp.length && !this.priorHigher(opTop, this.infix[i])) {
                this.suffix.push(temp.pop());
                opTop = temp[temp.length - 1];
              }
            }
              // 将当前运算符也压入后缀表达式
            temp.push(this.infix[i]);
          }
        }
      }
      // 将剩余运算符号压入
      while (temp.length) {
        this.suffix.push(temp.pop());
      }
    },
// 后缀表达式计算
    calcSuffix: function() {
      this.result = [];

      for (var i = 0; i < this.suffix.length; i++) {
        // 数值,直接压入结果集
        if (!this.isOp(this.suffix[i])) {
          this.result.push(this.suffix[i]);
        }
        // 运算符,从结果集中取出两项进行运算,并将运算结果置入结果集合
        else {
          this.result.push(this.opCalc(this.result.pop(), this.suffix[i], this.result.pop()));
        }
      }
      // 此时结果集中只有一个值,即为结果
       return this.result[0];
    }

其实,在实现的时候会发现,中缀、后缀只是一个难点,更复杂的地方是整个计算器的状态变化(或者说是数据变化)

在这个简单的计算器中,就有数字(0-9)、运算符(+ - * /)、操作(清除 删除)、预运算(百分号 平方)、小数点、即时运算等数据及操作

如果是科学计算器那就更复杂了,所以理清如何控制这些东西很关键,而其中最重要的就是中缀表达式的构建与存储

 当连续点击+号时,是不符合实际操作的,所以需要一个变量 lastVal 来记录上一个值,随着操作而更新,再通过判断,防止程序出错

在点击=号之后,我们可以继续使用这个结果进行运算,或者重新开始运算

// 构建中缀表达式
    buildInfix: function(val, type) {
      // 直接的点击等于运算之后,
      if (this.calcDone) {
        this.calcDone = false;
        // 再点击数字,则进行新的运算
        if (!this.isOp(val)) {
          this.resetData();
        }
        // 再点击运算符,则使用当前的结果值继续进行运算
        else {
          var re = this.result[0];
          this.resetData();
          this.infix.push(re);
        }

      }

      var newVal;
       ...

点击删除,是删除一位数,不是直接地删除一个数,然后更新中缀表达式的值

// 删除操作
      if (type === 'del') {
        newVal = this.infix.pop();
        // 删除末尾一位数
        newVal = Math.floor(newVal / 10);
        if (newVal) {
          this.infix.push(newVal);
        }

        this.lastVal = this.infix[this.infix.length - 1];
        return this.infix;
      }

而添加操作,要考虑的就更多了,比如连续的连续运算符、连续的数字、运算符+ - 接上数字表示正负数,小数点的连接存取等

// 添加操作,首先得判断运算符是否重复
      else if (type === 'add') {
        // 两个连续的运算符
        if (this.isOp(val) && this.isOp(this.lastVal)) {
          return this.infix;
        }
        // 两个连续的数字
        else if (!this.isOp(val) && !this.isOp(this.lastVal)) {
          newVal = this.lastVal * 10 + val;
          this.infix.pop();
          this.infix.push(this.lastVal = newVal);

          return this.infix;
        }
        // 首个数字正负数
        if (!this.isOp(val) && this.infix.length === 1 && (this.lastVal === '+' || this.lastVal === '-')) {
          newVal = this.lastVal === '+' ? val : 0 - val;
          this.infix.pop();
          this.infix.push(this.lastVal = newVal);

          return this.infix;
        }


        this.infix.push(this.lastVal = val);
        return this.infix;
      }

在很多次操作的时候,计算器都需要即时地进行运算,为简化代码,可以封装成一个方法,在相应的位置调用即可

// 即时得进行运算
    calculate: function(type) {
      this.infix2Suffix();
      var suffixRe = this.calcSuffix();

      if (suffixRe) {
        this.$out.text('=' + suffixRe)
          .attr('title', suffixRe)
          .removeClass('active');

        // 如果是直接显示地进行等于运算
        if (type === 'eq') {
          this.$in.removeClass('active');
          this.$out.addClass('active');
          // 设置标记:当前已经显示地进行计算
          this.calcDone = true;
          this.lastVal = suffixRe;
          // 设置历史记录
          var history = this.infix.join('') + ' = ' + suffixRe;
          this.$history.text(history).attr('title', history);
        }

      }
    },

剩下的就是点击之后的处理过程了,也就是各种调用处理 传递数据->构建中缀处理数据->中缀转后缀->后缀运算显示

比如点击了数字

// 数字:0-9
          if (!isNaN(parseInt(val, 10))) {
            // 构建中缀表达式并显示
            var infixRe = that.buildInfix(parseInt(val, 10), 'add');
            that.$in.text(infixRe.join('')).addClass('active');

            that.calculate();

            return;
          }

又比如几个预运算,其实长得也差不多

// 预运算:百分比、小数点、平方
          else if (['per', 'dot', 'sq'].indexOf(action) !== -1) {
            if (!that.infix.length || that.isOp(that.lastVal)) {
              return;
            }

            if (action === 'per') {
              that.lastVal /= 100;
            } else if (action === 'sq') {
              that.lastVal *= that.lastVal;
            } else if (action === 'dot') {
              // that.curDot = true;
            }

            // 重新构建中缀表达式
            var infixRe = that.buildInfix(that.lastVal, 'change');
            that.$in.text(infixRe.join('')).addClass('active');

            that.calculate();
          }

以上就是这个简单计算器的实现步骤了,变化太多还不敢保证不会出错

基本逻辑如此,如果要加上小数点运算、括号运算、正余弦等科学计算器的功能,还是自己去实现吧。。脑大啊。。 

$(function() {

  function Calculator($dom) {
    this.$dom = $($dom);
    // 历史运算
    this.$history = this.$dom.find('.calc-history');
    // 输入区
    this.$in = this.$dom.find('.calc-in');
    // 输出区
    this.$out = this.$dom.find('.calc-out');
    this.$operation = this.$dom.find('.calc-operation');

    // 运算符映射
    this.op = {
      'plus': '+',
      'minus': '-',
      'mul': '*',
      'div': '/'
    };
    this.opArr = ['+', '-', '*', '/'];

    // 中缀表达式
    this.infix = [];
    // 后缀表达式
    this.suffix = [];
    // 后缀表达式运算结果集
    this.result = [];
    // 存储最近的值
    this.lastVal = 0;
    // 当前已经计算等于完成
    this.calcDone = false;
    // 当前正在进行小数点点(.)相关值的修正
    this.curDot = false;

    this.init();
  }

  Calculator.prototype = {
    constructor: Calculator,
    // 初始化
    init: function() {
      this.bindEvent();
    },
    // 绑定事件
    bindEvent: function() {
      var that = this;

      that.$operation.on('click', function(e) {
        e = e || window.event;
        var elem = e.target || e.srcElement,
          val,
          action;

        if (elem.tagName === 'TD') {
          val = elem.getAttribute('data-val') || elem.getAttribute('data-ac');
          // 数字:0-9
          if (!isNaN(parseInt(val, 10))) {
            // 构建中缀表达式并显示
            var infixRe = that.buildInfix(parseInt(val, 10), 'add');
            that.$in.text(infixRe.join('')).addClass('active');

            that.calculate();

            return;
          }

          action = val;

          // 操作:清除、删除、计算等于
          if (['cls', 'del', 'eq'].indexOf(action) !== -1) {
            if (!that.infix.length) {
              return;
            }

            // 清空数据
            if (action === 'cls' || (action === 'del' && that.calcDone)) {
              that.$in.text('');
              that.$out.text('');

              that.resetData();
            }
            // 清除
            else if (action === 'del') {
              // 重新构建中缀表达式
              var infixRe = that.buildInfix(that.op[action], 'del');
              that.$in.text(infixRe.join('')).addClass('active');

              that.calculate();

            }
            // 等于
            else if (action === 'eq') {
              that.calculate('eq');

            }
          }
          // 预运算:百分比、小数点、平方
          else if (['per', 'dot', 'sq'].indexOf(action) !== -1) {
            if (!that.infix.length || that.isOp(that.lastVal)) {
              return;
            }

            if (action === 'per') {
              that.lastVal /= 100;
            } else if (action === 'sq') {
              that.lastVal *= that.lastVal;
            } else if (action === 'dot') {
              // that.curDot = true;
            }

            // 重新构建中缀表达式
            var infixRe = that.buildInfix(that.lastVal, 'change');
            that.$in.text(infixRe.join('')).addClass('active');

            that.calculate();
          }
          // 运算符:+ - * /
          else if (that.isOp(that.op[action])) {
            if (!that.infix.length && (that.op[action] === '*' || that.op[action] === '/')) {
              return;
            }

            var infixRe = that.buildInfix(that.op[action], 'add');
            that.$in.text(infixRe.join('')).addClass('active');
          }
        }
      });
    },

    resetData: function() {
      this.infix = [];
      this.suffix = [];
      this.result = [];
      this.lastVal = 0;
      this.curDot = false;
    },

    // 构建中缀表达式
    buildInfix: function(val, type) {
      // 直接的点击等于运算之后,
      if (this.calcDone) {
        this.calcDone = false;
        // 再点击数字,则进行新的运算
        if (!this.isOp(val)) {
          this.resetData();
        }
        // 再点击运算符,则使用当前的结果值继续进行运算
        else {
          var re = this.result[0];
          this.resetData();
          this.infix.push(re);
        }

      }

      var newVal;

      // 删除操作
      if (type === 'del') {
        newVal = this.infix.pop();
        // 删除末尾一位数
        newVal = Math.floor(newVal / 10);
        if (newVal) {
          this.infix.push(newVal);
        }

        this.lastVal = this.infix[this.infix.length - 1];
        return this.infix;
      }
      // 添加操作,首先得判断运算符是否重复
      else if (type === 'add') {
        // 两个连续的运算符
        if (this.isOp(val) && this.isOp(this.lastVal)) {
          return this.infix;
        }
        // 两个连续的数字
        else if (!this.isOp(val) && !this.isOp(this.lastVal)) {
          newVal = this.lastVal * 10 + val;
          this.infix.pop();
          this.infix.push(this.lastVal = newVal);

          return this.infix;
        }
        // 首个数字正负数
        if (!this.isOp(val) && this.infix.length === 1 && (this.lastVal === '+' || this.lastVal === '-')) {
          newVal = this.lastVal === '+' ? val : 0 - val;
          this.infix.pop();
          this.infix.push(this.lastVal = newVal);

          return this.infix;
        }

      // TODO: 小数点运算
      //   if (this.isOp(val)) {
      //     this.curDot = false;
      //   }

      //   // 小数点
      //   if (this.curDot) {
      //     var dotLen = 0;
      //     newVal = this.infix.pop();
      //     dotLen = newVal.toString().split('.');
      //     dotLen = dotLen[1] ? dotLen[1].length : 0;

      //     newVal += val / Math.pow(10, dotLen + 1);
      //     // 修正小数点运算精确值
      //     newVal = parseFloat(newVal.toFixed(dotLen + 1));

      //     this.infix.push(this.lastVal = newVal);
      //     return this.infix;
      //   }

        this.infix.push(this.lastVal = val);
        return this.infix;
      }

      // 更改操作,比如%的预运算
      else if (type === 'change') {
        this.infix.pop();
        this.infix.push(this.lastVal = val);

        return this.infix;
      }

    },
    // 判断是否为运算符
    isOp: function(op) {
      return op && this.opArr.indexOf(op) !== -1;
    },
    // 判断运算符优先级
    priorHigher: function(a, b) {
      return (a === '+' || a === '-') && (b === '*' || b === '/');
    },
    // 进行运算符的运算
    opCalc: function(b, op, a) {
      return op === '+'
        ? a + b
        : op === '-'
        ? a - b
        : op === '*'
        ? a * b
        : op === '/'
        ? a / b
        : 0;
    },
    // 即时得进行运算
    calculate: function(type) {
      this.infix2Suffix();
      var suffixRe = this.calcSuffix();

      if (suffixRe) {
        this.$out.text('=' + suffixRe)
          .attr('title', suffixRe)
          .removeClass('active');

        // 如果是直接显示地进行等于运算
        if (type === 'eq') {
          this.$in.removeClass('active');
          this.$out.addClass('active');
          // 设置标记:当前已经显示地进行计算
          this.calcDone = true;
          this.lastVal = suffixRe;
          // 设置历史记录
          var history = this.infix.join('') + ' = ' + suffixRe;
          this.$history.text(history).attr('title', history);
        }

      }
    },

    // 中缀表达式转后缀
    infix2Suffix: function() {
      var temp = [];
      this.suffix = [];

      for (var i = 0; i < this.infix.length; i++) {
        // 数值,直接压入
        if (!this.isOp(this.infix[i])) {
          this.suffix.push(this.infix[i]);
        }
        else {
          if (!temp.length) {
            temp.push(this.infix[i]);
          }
          else {
            var opTop = temp[temp.length - 1];
            // 循环判断运算符优先级,将运算符较高的压入后缀表达式
            if (!this.priorHigher(opTop, this.infix[i])) {
              while (temp.length && !this.priorHigher(opTop, this.infix[i])) {
                this.suffix.push(temp.pop());
                opTop = temp[temp.length - 1];
              }
            }
              // 将当前运算符也压入后缀表达式
            temp.push(this.infix[i]);
          }
        }
      }
      // 将剩余运算符号压入
      while (temp.length) {
        this.suffix.push(temp.pop());
      }
    },

    // 后缀表达式计算
    calcSuffix: function() {
      this.result = [];

      for (var i = 0; i < this.suffix.length; i++) {
        // 数值,直接压入结果集
        if (!this.isOp(this.suffix[i])) {
          this.result.push(this.suffix[i]);
        }
        // 运算符,从结果集中取出两项进行运算,并将运算结果置入结果集合
        else {
          this.result.push(this.opCalc(this.result.pop(), this.suffix[i], this.result.pop()));
        }
      }
      // 此时结果集中只有一个值,即为结果
       return this.result[0];
    }
  };

  new Calculator('.calc-wrap');
});

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
Jan 13 Javascript
js跑马灯代码(自写)
Apr 17 Javascript
jQuery判断元素是否存在的可靠方法
May 06 Javascript
浅析BootStrap模态框的使用(经典)
Apr 29 Javascript
纯javascript版日历控件
Nov 24 Javascript
Angularjs实现分页和分页算法的示例代码
Dec 23 Javascript
微信小程序实现页面跳转传值的方法
Oct 12 Javascript
JavaScript实现的九种排序算法
Mar 04 Javascript
手把手教你使用TypeScript开发Node.js应用
May 06 Javascript
JS实现打字游戏
Dec 17 Javascript
在vue中获取wangeditor的html和text的操作
Oct 23 Javascript
antd-日历组件,前后禁止选择,只能选中间一部分的实例
Oct 29 Javascript
用自定义图片代替原生checkbox实现全选,删除以及提交的方法
Oct 18 #Javascript
jquery中用jsonp实现搜索框功能
Oct 18 #Javascript
JavaScript排序算法动画演示效果的实现方法
Oct 18 #Javascript
浅谈js的异步执行
Oct 18 #Javascript
Jquery AJAX POST与GET之间的区别详细介绍
Oct 17 #Javascript
微信小程序 教程之模块化
Oct 17 #Javascript
微信小程序 教程之注册页面
Oct 17 #Javascript
You might like
PHP高级OOP技术演示
2009/08/27 PHP
php读取3389的脚本
2014/05/06 PHP
使用ThinkPHP+Uploadify实现图片上传功能
2014/06/26 PHP
PHP和Mysql中转UTF8编码问题汇总
2015/10/10 PHP
你需要知道的JavsScript可以做什么?
2007/06/29 Javascript
10个新的最有前途的JavaScript框架
2009/03/12 Javascript
jQuery操作表格(table)的常用方法、技巧汇总
2014/04/12 Javascript
vue全局组件与局部组件使用方法详解
2018/03/29 Javascript
JavaScript中变量提升与函数提升经典实例分析
2018/07/26 Javascript
vue中Axios的封装与API接口的管理详解
2018/08/09 Javascript
详解JS预解析原理
2020/06/16 Javascript
[52:52]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第三局
2016/02/27 DOTA
[01:14:30]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第二场 8.20.mp4
2019/08/22 DOTA
python 算法 排序实现快速排序
2012/06/05 Python
Python实现爬取知乎神回复简单爬虫代码分享
2015/01/04 Python
Python中装饰器的一个妙用
2015/02/08 Python
Python实现单词拼写检查
2015/04/25 Python
Python使用装饰器进行django开发实例代码
2018/02/06 Python
完美解决安装完tensorflow后pip无法使用的问题
2018/06/11 Python
Tensorflow 实现分批量读取数据
2020/01/04 Python
python矩阵运算,转置,逆运算,共轭矩阵实例
2020/05/11 Python
Keras保存模型并载入模型继续训练的实现
2021/02/20 Python
html5版canvas自由拼图实例
2014/10/15 HTML / CSS
Hunkemöller西班牙:欧洲最大的内衣连锁店
2018/08/15 全球购物
香港通票:Hong Kong Pass
2019/02/26 全球购物
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
给老师的道歉信
2014/01/11 职场文书
考试不及格的检讨书
2014/01/22 职场文书
八一建军节活动方案
2014/02/10 职场文书
个人充满哲理的自我评价
2014/02/20 职场文书
学生上课看漫画的检讨书
2014/09/26 职场文书
实习生矿工检讨书
2014/10/13 职场文书
2016年社会管理综治宣传月活动总结
2016/03/16 职场文书
2019年第四季度财务部门工作计划
2019/11/02 职场文书
漫改真人电影「萌系男友是燃燃的橘色」公开先导视觉图
2022/03/21 日漫
Android Flutter实现图片滑动切换效果
2022/04/07 Java/Android