JavaScript 俄罗斯方块游戏实现方法与代码解释


Posted in Javascript onApril 08, 2020

本文实例讲述了JavaScript 俄罗斯方块游戏。分享给大家供大家参考,具体如下:

俄罗斯方块代码说明

/**
  名称:Javascript 俄罗斯方块!
  作者:Gloot
  邮箱:glootz@gmail.com 
   QQ:345268267 
  网站:http://www.cnblogs.com/editor/
*/

OLSFK = {};

本俄罗斯方块代码采用 JavaScript 脚本代码写成,简单易懂;

全代码采用静态类及静态变量成员组成;

全脚本通过实现代码全局配置 OLSFK.Options = {...}

定义方块起始坐标及定义各自的旋转点;

从初始化俄罗斯方块界面开始,再监听键盘事件;以及左右,向下及旋转动作判断,重新渲染方块位置;

判断是否消行,以及相应的加级判断,执行速度,加分操作来执行;

最后以判断是否当前级别大于所定义的最大级别来判断是否结束;

代码说明讲解

OLSFK.Options = { //相关参数
  width:12,//界面横向方块数
  height:20,//界面纵向方块数
  boxWidth : '16px',
  curLevel:1,
  speed : 1000, //setInterval,setTimeout
  direct : { //可以设定是A S D W, 还是← ↓ → 
    Down: 40 , /*run speed*/
    Left: 37,
    Right: 39,
    Rotate: 38
  },
  Move:true,//是否正在移动
  Eventing:false,
  Levels: {
    1:1000,
    2:900,
    3:800,
    4:700,
    5:600,
    6:500,
    7:400,
    8:300,
    9:200,
    10:100
  },
  curBlock:4, //当前移动的图形名称
  nextBlock:0,
  GampMap:new Object(),
  Timer:null,
  deline:0,
  Score:0,
  Deling:false,
  Start:false,
  lineNum:10, //删除几行了,加级
  ScoreNum:40 //消一行加分
}

direct 表示 使用键盘方位键来操作方块的移动方向;

使用哪种方向键按自由喜欢配置,比如字母键的A, S, D, W; 或右边小数字键盘的数字键各自的键盘编码;

比如 上(旋转)、下、左、右 方向键的编码分别为:38、40、37、39;

Levels:表示级别配置,本配置共分为10级,每个级别所对应的下落速度,即定时执行间隔;

curBlock:表示当前活动的方块;

nextBlock:表示接下来执行的方块索引,并显示界面右上角的预览框中;

GampMap:用于保存在根据定义行列数形成的游戏表格中保存每个格的数据信息;

OLSFK.Options.GampMap[x+'_'+y] = 0;

对象表格为: id: "box_"+x+"_"+y;

初始化数据为 ‘0';  表示该表格还未占用;当有占用时,设置值为 ‘1';

Timer:为定时执行器;setTimeout 定时执行方块下落的的频率;定时时间越小,速度越快;

Deling:当正在执行消行操作时,下次暂不显示并下落;

lineNum:表示消超过 10 行,加一级;

ScoreNum:表示每消一行所加的分数;

OLSFK.ReItems = function (cur){ //key旋转点
  
  switch (cur)
  {
    case 1:
      OLSFK.Items[1] = {//长块 LongBlock
                1:{x:4,y:0},
                2:{x:5,y:0},
                3:{x:6,y:0},
                4:{x:7,y:0},
                5:{x:5,y:0} //旋转点
              };
      break;
            //....
    }
}

该方法用于恢复方块的初始设置;

OLSFK.Next = { //key旋转点
  //长块 LongBlock
  1: {
    1:{x:0,y:1},
    2:{x:1,y:1},
    3:{x:2,y:1},
    4:{x:3,y:1}
  },
    //...
}

为不了不与游戏方块的设置冲突,独立出来下次随机方块的对象配置;

OLSFK.Items = { //key旋转点
  //长块 LongBlock
  1: {
    1:{x:4,y:0},
    2:{x:5,y:0},
    3:{x:6,y:0},
    4:{x:7,y:0},
    5:{x:5,y:0}
  },
  //方块Box
  2: {
    1:{x:4,y:0},
    2:{x:5,y:0},
    3:{x:4,y:1},
    4:{x:5,y:1},
    5:{x:0,y:0}
  },
  //凸块 TuBlock
  3: {
    1:{x:4,y:1},
    2:{x:5,y:0},
    3:{x:5,y:1},
    4:{x:6,y:1},
    5:{x:5,y:1}
  },
  //L块 LBlock
  4: {
    1:{x:5,y:0},
    2:{x:5,y:1},
    3:{x:5,y:2},
    4:{x:6,y:2},
    5:{x:5,y:2}
  },
  5: { //反向L块 FLBlock
    1:{x:5,y:2},
    2:{x:6,y:2},
    3:{x:6,y:1},
    4:{x:6,y:0},
    5:{x:6,y:2}
  },
  //Z块 ZBlock
  6: {
    1:{x:4,y:0},
    2:{x:5,y:0},
    3:{x:5,y:1},
    4:{x:6,y:1},
    5:{x:5,y:0}
  },
  7: {//反向Z块 FZBlock
    1:{x:4,y:1},
    2:{x:5,y:1},
    3:{x:5,y:0},
    4:{x:6,y:0},
    5:{x:5,y:1}
  }
}

方块共分为:长条块,方块,凸块(T块),L块,反L块,Z块,反Z块几种;

共7种方块,以1,2,3,4,5,6,7 索引键表示,方块是四个小块组成,每块都有各自的坐标,1-4表示组成该块的初始坐标位置,5表示旋转点;

OLSFK.Init = function() { //初始化界面
  //...
}

俄罗斯方块的界面初始化方法;将在 window.onload 中调用执行;

var w = OLSFK.Options.width;
  var h = OLSFK.Options.height;
  var total = w * h;

  var x=0,y=0;
  for (var i=0; i<total; i++)
  {
    
    OLSFK.Options.GampMap[x+'_'+y] = 0;

    Lib.Tag('SPAN',{id:"box_"+x+"_"+y,name:"cbox",style:{
      width:OLSFK.Options.boxWidth,
      height:OLSFK.Options.boxWidth,
      border:"2px outset #669",
      background:"#ddd",
      float:"left",
      overflow:"hidden"
    },innerHTML:" ",className:"cssbox"},back);

    var end = i + 1;
    x++;
    if (end >= w && end % w == 0)
    {
      x=0;
      y++;
      Lib.Tag('DIV',{style:{
        clear:"both"
      }},back);
    }

  }

通过设置的 Options.width, Options.height 列数与行数,以及设置的小方格宽度,初始化了一个宽:Options.width列,高为 Options.height 的表格界面出来;

Lib.Tag 用于创建标签对象;

Lib.Tag = function(TAG,json,pnode) {
  //...
}

TAG为标签名,比如: div, span 等;

json为设置标签样式 style;

pnode 是该创建所在的父容器;

OLSFK.Init = function() {} 还创建主游戏区域旁边的下次随机方块预览区,当前级别,及分数,以及操作“开始”,“暂停”按钮等;

JavaScript 俄罗斯方块游戏实现方法与代码解释

游戏初始入口点

window.onload = function() {
  if (window.isIE)
  {
    document.attachEvent("onkeydown",function(e) {
      if (OLSFK.Options.Start)
      {
        var E = OLSFK.KeyCode();
        OLSFK.EventFunc(E);
      }

    });

    document.attachEvent("onkeyup",function(e) {
      if (!OLSFK.Options.Move && OLSFK.Options.Start)
      {
        OLSFK.Options.Move = true;
        OLSFK.Options.Eventing = false;

        OLSFK.Options.Timer = setTimeout(function() {
          OLSFK.play();
        }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
      }
    });
  } else {
    document.addEventListener("keydown",function(e) {

      if (OLSFK.Options.Start)
      {
        var E = OLSFK.KeyCode();
        OLSFK.EventFunc(E);
      }
      
    },false);

    document.addEventListener("keyup",function(e) {
      if (!OLSFK.Options.Move && OLSFK.Options.Start)
      {
        OLSFK.Options.Move = true;
        OLSFK.Options.Eventing = false;

        OLSFK.Options.Timer = setTimeout(function() {
          OLSFK.play();
        }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
      }
    },false);
  }
  OLSFK.Init();
}

主要是监听键盘事件,根据 键盘事件 返回的按钮编码与 OLSFK.Options.direct 设置方向键匹配来操作方块的移动,旋转等;

keydown 用于操作下落方块的移动方向,旋转等;并重新绘制方块位置;

keyup 后继续按本级速度向下落;

OLSFK.Options.Levels[OLSFK.Options.curLevel]

表示当前级别对应的速度,即定时器间隔执行时间(毫秒);

OLSFK.EventFunc = function(code) {
  switch (code)
  {
    case OLSFK.Options.direct.Left: //LEFT
      if (!OLSFK.Options.Deling)
      {
        clearTimeout(OLSFK.Options.Timer);
        OLSFK.Options.Eventing = true;
        OLSFK.Options.Move = false;
        OLSFK.Left();
      }

      break;
      //...
    }
}

该方法是 监听 keydown 事件执行的动作;code 为按键 编码;

当判断未在消行动作时,清除定时器,OLSFK.Options.Eventing 设置为事件中 true,OLSFK.Options.Move 为 false 表示停止移动;

进入 向左移动方法 OLSFK.Left();

OLSFK.Left = function() {
  var block = OLSFK.Items[OLSFK.Options.curBlock];

  if (block)
  {
    var flag = true;
    for (var i=1; i<=4; i++)
    {
      var x = block[i].x;
      var y = block[i].y;

      if (x-1 < 0)
      {
        flag = false;
        break;
      }
      
      if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))
      {
        flag = false;
        break;
      }
    }

    if (flag)
    {
      for (var i=1; i<=4; i++) //清除图形
      {
        var itm = block[i];
        var box = Lib.Getid('box_'+itm.x+'_'+itm.y);

        box.style.background = '#ddd';
        OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
      }

      for (var i=1; i<=5; i++)
      {
        var x = block[i].x;
        var y = block[i].y;

        OLSFK.Items[OLSFK.Options.curBlock][i] = {x:(x-1),y:y};
      }
      
      OLSFK.draw();
    } 
  }
}

var block = OLSFK.Items[OLSFK.Options.curBlock]; 表示获取当前移动方块;

if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))
{
  flag = false;
  break;
}

判断该方块四个小方块左边是否有被占用的方块,也即: OLSFK.Options.GampMap[(x-1)+'_'+y] 为 1; 并且该位置块不属于方块自己的;

当左边方向无占用格时,清除当前方块四个小方块位置,重新绘制方块新坐标位置;并重置 相应的 OLSFK.Options.GameMap [x+y] 相应格的值;

当按钮 keyup 时,继承正常向下落;

OLSFK.isMe 代码:

OLSFK.isMe = function(x,y) {
  var block = OLSFK.Items[OLSFK.Options.curBlock];

  if (block)
  {
    for (var i=1; i<=4; i++)
    {
      if (block[i].x == x && block[i].y == y)
      {
        return true;
      }
    }
  }

  return false;
}

即指定的 x,y (参数值) 是否还在当前方块四个坐标内;

OLSFK.Right () 与 Left() 一样;

旋转方块代码;

OLSFK.Rotate = function() {
  var block = OLSFK.Items[OLSFK.Options.curBlock];

  if (block)
  {
    var flag = true;

    var R = block[5];
    for (var i=1; i<=4; i++)
    {
      var x = block[i].x;
      var y = block[i].y;

      if (R.x == x && R.y == y)
      {
        
      } else {
        var nson = new Object();

        nson.x = R.x + R.y - y;
        nson.y = R.y - R.x + x;

        if ( nson.x < 0 || nson.y < 0 || nson.x >= OLSFK.Options.width || nson.y >= OLSFK.Options.height )
        {
          flag = false;
          break;
        }

        if (OLSFK.Options.GampMap[nson.x+'_'+nson.y] == 1 && !OLSFK.isMe(nson.x,nson.y))
        {
          flag = false;
          break;
        }
      }
    }

    if (flag)
    {
      for (var i=1; i<=4; i++) //清除图形
      {
        var itm = block[i];
        var box = Lib.Getid('box_'+itm.x+'_'+itm.y);

        box.style.background = '#ddd';
        OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
      }

      var Pnt = 1;

      for (var i=1; i<=4; i++)
      {
        var x = block[i].x;
        var y = block[i].y;
        
        if (R.x == x && R.y == y)
        {
          Pnt = i;
        } else {
          var nson = new Object();

          nson.x = R.x + R.y - y;
          nson.y = R.y - R.x + x;
          OLSFK.Items[OLSFK.Options.curBlock][i] = {x:nson.x,y:nson.y};
        }
      }

      OLSFK.Items[OLSFK.Options.curBlock][5] = OLSFK.Items[OLSFK.Options.curBlock][Pnt];
      
      OLSFK.draw();
    } 
  }
}

var R = block[5]; 就是获取旋转点;

就开始对方块四个小块以旋转点为中心,逆时针旋转(并不全是 90 度);当当前块不为旋转点时,旋转公式;

var nson = new Object();

nson.x = R.x + R.y - y;
nson.y = R.y - R.x + x;

这个公式要这样看;

ResultX = RotateX + (RotateY - CurrentY);
ResultY = RotateY - (RotateX - CurrentX);

//Y的偏移量,就是X的增加值;
//反之同

当旋转四周都无占用物时;清除当前图形,重绘旋转后的图形位置;

重置 OLSFK.Options.GampMap[itm.x+'_'+itm.y] 各个方块的占用值;

OLSFK.Random = function() {

  if (OLSFK.Options.nextBlock != 0)
  {
    OLSFK.Options.curBlock = OLSFK.Options.nextBlock;

    var block = OLSFK.Next[OLSFK.Options.nextBlock];
    if (block)
    {
      for (var i=1; i<=4; i++)
      {
        var itm = block[i];
        var box = Lib.Getid('cur_'+itm.x+'_'+itm.y);

        box.style.background = '#ddd';
        //OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
      }
    }
  } else {
    OLSFK.Options.curBlock = Math.floor(Math.random() * 7 + 1);
  }
  OLSFK.Options.nextBlock = Math.floor(Math.random() * 7 + 1);

  OLSFK.drawNext();
}

随机生成下次预下落的方块;并显示到右上角的预览表格里;

OLSFK.play = function(speed) {
  var block = OLSFK.Items[OLSFK.Options.curBlock];

  if (block && OLSFK.Options.Move)
  {

    var flag = true;
    for (var i=1; i<=4; i++)
    {
      var x = block[i].x;
      var y = block[i].y;

      if (y+1 >= OLSFK.Options.height)
      {
        flag = false;
        break;
      }
      
      if (OLSFK.Options.GampMap[x+'_'+(y+1)] == 1 && !OLSFK.isMe(x,y+1))
      {
        flag = false;
        break;
      }
    }
    
    if (flag)
    {
      for (var i=1; i<=4; i++) //清除图形
      {
        var itm = block[i];
        var box = Lib.Getid('box_'+itm.x+'_'+itm.y);

        box.style.background = '#ddd';
        OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
      }

      for (var i=1; i<=5; i++)
      {
        var x = block[i].x;
        var y = block[i].y;

        OLSFK.Items[OLSFK.Options.curBlock][i] = {x:x,y:(y+1)};
      }
      OLSFK.draw();
      
      var S = OLSFK.Options.Levels[OLSFK.Options.curLevel];
      if (speed)
      {
        S = 50;
      }
      OLSFK.Options.Timer = setTimeout(function() {
        OLSFK.play();
      }, S);
    } else {
      OLSFK.ReItems(OLSFK.Options.curBlock);
      OLSFK.newRun();
    }
  }
}

OLSFK.play 正常下落的方法,也得判断下落一格是否有被占用的格,如果没有,清除当前方块,绘制方块新位置;

当方块不能再下落时(flag = false),重置当前方块坐标配置; OLSFK.ReItems(OLSFK.Options.curBlock);

进入 OLSFK.newRun(); 新下落方块下落过程准备;

OLSFK.newRun = function() {

  clearTimeout(OLSFK.Options.Timer);
  OLSFK.DelFunc();
  if (OLSFK.Options.deline >= 10)
  {
    OLSFK.Options.deline = 0;
    OLSFK.Options.curLevel ++;
    OLSFK.Element.CurLevel.setHTML("级:"+OLSFK.Options.curLevel);
  }
  OLSFK.Element.Score.setHTML("分:"+OLSFK.Options.Score);

  if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)
  {
    OLSFK.Random();
    //判断是否结束
    OLSFK.ChkEnd();
  } else {
    OLSFK.Options.Move = false;
    OLSFK.Options.Start = false;
    OLSFK.Options.Eventing = false;
    OLSFK.Options.Deling = false;
    Lib.Getid('spn').innerHTML = 'Game Is Over! You Win the Game!';

    Lib.Getid('dobtn').innerHTML = ' 开始 ';
  }
  
}

当下落结束时,清除定时器,暂停新方块下落,检测是否有可消除的行;减了多少行;

每减去一行 加分

OLSFK.Options.Score += OLSFK.Options.ScoreNum;

这个方法在 :

OLSFK.DelFunc = function() {
  OLSFK.Options.Deling = true;
  OLSFK.Options.Move = false;
  OLSFK.Options.Eventing = false;
  var Fn = 0;
  for (var i=OLSFK.Options.height-1; i>=0; i--)
  {
    Fn = 0;
    for (var j=0; j<OLSFK.Options.width; j++)
    {
      if (OLSFK.Options.GampMap[j+'_'+i] == 1)
      {
        Fn++;
      }
    }

    if (Fn == OLSFK.Options.width)
    {
      OLSFK.Options.deline ++;
      OLSFK.Options.Score += OLSFK.Options.ScoreNum;
      OLSFK.DelLine(i);
      i++;
    }
  }
  OLSFK.Options.Deling = false;
  OLSFK.Options.Move = true;
  OLSFK.Options.Eventing = true;
}

中执行;

减完一行,就重置该行以上所有行往下降一行;并重置 :

OLSFK.Options.GampMap[x+'_'+y] = OLSFK.Options.GampMap[x+'_'+(y-1)];

该减行为上行的数据;

if (Fn == OLSFK.Options.width)
    {
      OLSFK.Options.deline ++;
      OLSFK.Options.Score += OLSFK.Options.ScoreNum;
      OLSFK.DelLine(i);
      i++;
    }

该判断表示该行上所有格都被占用到;

回到 newRun 上,当判断消行超过几行时,即加级;

if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)
  {
    OLSFK.Random();
    //判断是否结束
    OLSFK.ChkEnd();
  }

如果级数小于配置的总级数,则进入 OLSFK.random();

设置当前下落方块,并随机生成下次下落方块并预览右上角表格上;

OLSFK.ChkEnd = function() {
  var block = OLSFK.Items[OLSFK.Options.curBlock];

  if (block && OLSFK.Options.Move)
  {

    var flag = true;
    for (var i=1; i<=4; i++)
    {
      var x = block[i].x;
      var y = block[i].y;
      
      if (OLSFK.Options.GampMap[x+'_'+y] == 1)
      {
        flag = false;
        break;
      }
    }
  }

  if (flag )
  {
    OLSFK.draw();

    //定时往下掉
    OLSFK.Options.Timer = setTimeout(function() {
      OLSFK.play();
    }, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
  } else {
    OLSFK.Options.Move = false;
    OLSFK.Options.Start = false;
    OLSFK.Options.Eventing = false;
    OLSFK.Options.Deling = false;
    Lib.Getid('spn').innerHTML = 'Game Is Over';

    Lib.Getid('dobtn').innerHTML = ' 开始 ';
  }
}

当当前下落的方块进入表格上有被占用的格子,即被卡住,游戏结束;

反之 则 setTimeout 开始新方块的下落动作;

其他方法说明

OLSFK.Event = function() {
  if (window.isIE)
    return window.event;
  func = OLSFK.Event.caller; 

  while(func!=null) 
  {
    var arg0=func.arguments[0]; 
    if(arg0) 
    {
      return arg0; 
    }
    func=func.caller; 
  }
  return null; 
}

OLSFK.KeyCode = function() {
  return OLSFK.Event().keyCode || OLSFK.Event().which;
}

OLSFK.Event = function();

这是一种获取当前事件的方法,可以比较兼容获取当前的事件;

俄罗斯方块 JavaScript 代码

点击此处本站下载

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
jQuery代码优化 遍历篇
Nov 01 Javascript
删除select中所有option选项jquery代码
Aug 12 Javascript
JS将秒换成时分秒实现代码
Sep 03 Javascript
直接拿来用的页面跳转进度条JS实现
Jan 06 Javascript
IONIC自定义subheader的最佳解决方案
Sep 22 Javascript
浅析Node.js:DNS模块的使用
Nov 23 Javascript
JS 对java返回的json格式的数据处理方法
Dec 05 Javascript
Vue.js实现多条件筛选、搜索、排序及分页的表格功能
Nov 24 Javascript
angular.js指令中的controller、compile与link函数的不同之处
May 10 Javascript
JavaScript解析任意形式的json树型结构展示
Jul 23 Javascript
Vue页面渲染中key的应用实例教程
Jan 12 Vue.js
解决vue中provide inject的响应式监听
Apr 19 Vue.js
vue与iframe之间的信息交互的实现
Apr 08 #Javascript
Javascript摸拟自由落体与上抛运动原理与实现方法详解
Apr 08 #Javascript
antd-mobile ListView长列表的数据更新遇到的坑
Apr 08 #Javascript
详解element上传组件before-remove钩子问题解决
Apr 08 #Javascript
javascript 设计模式之享元模式原理与应用详解
Apr 08 #Javascript
javascript 设计模式之组合模式原理与应用详解
Apr 08 #Javascript
JS async 函数的含义和用法实例总结
Apr 08 #Javascript
You might like
递归实现php数组转xml的代码分享
2015/05/14 PHP
用JavaScript事件串连执行多个处理过程的方法
2007/03/09 Javascript
用javascript获取textarea中的光标位置
2008/05/06 Javascript
node.js中的buffer.length方法使用说明
2014/12/14 Javascript
JavaScript中的acos()方法使用详解
2015/06/14 Javascript
jquery实现浮动在网页右下角的彩票开奖公告窗口代码
2015/09/04 Javascript
JS如何判断是否为ie浏览器的方法(包括IE10、IE11在内)
2015/12/13 Javascript
jquery表格datatables实例解析 直接加载和延迟加载
2016/08/12 Javascript
Javascript实现代码折叠功能
2016/08/25 Javascript
怎样判断jQuery当前元素是隐藏还是显示
2016/11/23 Javascript
ionic 3.0+ 项目搭建运行环境的教程
2017/08/09 Javascript
vue jsx 使用指南及vue.js 使用jsx语法的方法
2017/11/11 Javascript
5分钟快速掌握JS中var、let和const的异同
2018/09/19 Javascript
详解基于Vue的支持数据双向绑定的select组件
2019/09/02 Javascript
vue 使用v-for进行循环的实例代码详解
2020/02/19 Javascript
vue-resource post数据时碰到Django csrf问题的解决
2020/03/13 Javascript
Angular8 简单表单验证的实现示例
2020/06/03 Javascript
js面试题之异步问题的深入理解
2020/09/20 Javascript
python正则表达式抓取成语网站
2013/11/20 Python
对web.py设置favicon.ico的方法详解
2018/12/04 Python
python+opencv实现摄像头调用的方法
2019/06/22 Python
Python3操作MongoDB增册改查等方法详解
2020/02/10 Python
Python networkx包的实现
2020/02/14 Python
Python 如何操作 SQLite 数据库
2020/08/17 Python
绘儿乐产品官方在线商店:Crayola.com
2019/09/07 全球购物
介绍一下OSI七层模型
2012/07/03 面试题
就业推荐表自我鉴定
2013/10/29 职场文书
入团者的自我评价分享
2013/12/02 职场文书
校园网站的创业计划书范文
2013/12/30 职场文书
七年级生物教学反思
2014/01/30 职场文书
幼儿园六一儿童节主持节目串词
2014/03/21 职场文书
合作协议书
2014/04/23 职场文书
秋天的图画教学反思
2014/05/01 职场文书
诉前财产保全担保书
2014/05/20 职场文书
银行大堂经理培训心得体会
2016/01/09 职场文书
使用vue-element-admin框架从后端动态获取菜单功能的实现
2021/04/29 Vue.js