VIP用户交流群:462197261 收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
在线客服:78895949
tonglan
  • 当前位置:
  • 原生JS使用Canvas实现拖拽式绘图功能

    建站教程 2019年11月09日 关键词:,,,,,

    一、实现的功能

    1、基于oop思想构建,支持坐标点、线条(由坐标点组成,包含方向)、多边形(由多个坐标点组成)、圆形(包含圆心坐标点和半径)等实体

    2、原生JavaScript实现,不依赖任何第三方js库和插件

    3、多图形绘制(支持画笔、线条、箭头、三角形、矩形、平行四边形、梯形以及多边形和圆形绘制)

    4、拖拽式绘制(鼠标移动过程中不断进行canvas重绘)

    5、图片绘制(作为背景图片时重绘会发生闪烁现象,暂时有点问题,后面继续完善)

    5、清空绘制功能

    6、新版本优化绘制性能(使用共享坐标变量数组,减少了大量的对象创建操作)

    7、新版本支持箭头绘制功能

    二、完整实现代码

    DrawingTools =(function(){
    //公共方法
          var getDom=function(id){return document.getElementById(id)};
          var isNull=function(s){return s==undefined||typeof(s)=='undefined'||s==null||s=='null'||s==''||s.length<1};
          var hideDefRM=function(){document.oncontextmenu=function(){return false}};//屏蔽浏览器默认鼠标事件
          /**绘图容器*/
          var cbtCanvas;
          /**绘图对象*/
          var cxt;
          /**绘制的图形列表*/
          var shapes=new Array();
          var graphkind={'cursor':0,'pen':1,'line':2,'trian':3,'rect':4,'poly':5,'circle':6,'arrow':21,'parallel':41,'trapezoid':42};
          //背景图片绘制配置
          var bgPictureConfig={
            pic:null,//背景图片地址或路径
            repaint:true,//是否作为永久背景图,每次清除时会进行重绘
          };
          //加载并绘制图片(src:图片路径或地址),默认重绘背景图
          var loadPicture=function(src){
            if(isNull(bgPictureConfig.repaint)||bgPictureConfig.repaint){bgPictureConfig.pic=src}
            var img = new Image();
            img.onload = function(){cxt.drawImage(img,0,0)}
            img.src =src;
          }
          //绘图基础配置
          var paintConfig={lineWidth:1,//线条宽度,默认1
            strokeStyle:'red',//画笔颜色,默认红色
            fillStyle:'red',//填充色
            lineJoin:"round",//线条交角样式,默认圆角
            lineCap:"round",//线条结束样式,默认圆角
          };
          //重新载入绘制样式
          var resetStyle=function(){
            cxt.strokeStyle=paintConfig.strokeStyle;
            cxt.lineWidth=paintConfig.lineWidth;
            cxt.lineJoin=paintConfig.lineJoin;
            cxt.lineCap=paintConfig.lineCap;
            cxt.fillStyle=paintConfig.fillStyle;
          }
          //鼠标图形
          var cursors=['crosshair','pointer'];
          /** 切换鼠标样式*/
          var switchCorser=function(b){
            cbtCanvas.style.cursor=((isNull(b)?isDrawing():b)?cursors[0]:cursors[1]);
          }
          //操作控制变量组
          var ctrlConfig={
            kind:0,//当前绘画分类
            isPainting:false,//是否开始绘制
            startPoint:null,//起始点
            cuGraph:null,//当前绘制的图像
            cuPoint:null,//当前临时坐标点,确定一个坐标点后重新构建
            cuAngle:null,//当前箭头角度
            vertex:[],//坐标点
          }
          /**获取当前坐标点*/
          var getCuPoint=function(i){
            return ctrlConfig.cuPoint[i];
          }
          /**设置当前坐标点*/
          var setCuPoint=function(p,i){
            return ctrlConfig.cuPoint[i]=p;
          }
          /**设置当前临时坐标点值*/
          var setCuPointXY=function(x,y,i){
            if(isNull(ctrlConfig.cuPoint)){
              var arr=new Array();
              arr[i]=new Point(x,y);
              ctrlConfig.cuPoint=arr;
            }else if(isNull(ctrlConfig.cuPoint[i])){
              setCuPoint(new Point(x,y),i);
            }else{
              ctrlConfig.cuPoint[i].setXY(x,y);
            }
            return getCuPoint(i);
          }
          /**是否正在绘制*/
          var isDrawing=function (){
            return ctrlConfig.isPainting;
          }
          /**开始绘制状态*/
          var beginDrawing=function(){
            ctrlConfig.isPainting=true;
          }
          /**结束绘制状态*/
          var stopDrawing=function(){
            ctrlConfig.isPainting=false;
          }
          /**是否有开始坐标点*/
          var hasStartPoint=function(){
            return !isNull(ctrlConfig.startPoint);
          }
          /**设置当前绘制的图形*/
          var setCuGraph=function(g){
            ctrlConfig.cuGraph=g;
          }
          /**获取当前绘制的图形*/
          var getCuGraph=function(){
            return ctrlConfig.cuGraph;
          }
          /**设置开始坐标点(线条的起始点,三角形的顶点,圆形的圆心,四边形的左上角或右下角,多边形的起始点)*/
          var setStartPoint=function(p){
            ctrlConfig.startPoint=p;
          }
          /**获取开始坐标点*/
          var getStartPoint=function(){
            return ctrlConfig.startPoint;
          }
          /**清空全部*/
          var clearAll=function(){
            cxt.clearRect(0,0,cbtCanvas.width,cbtCanvas.height);
          }
          /**重绘*/
          var repaint=function(){
            clearAll();
            /*
            if(bgPictureConfig.repaint){
              loadPicture(bgPictureConfig.pic);
            }*/
          }
          /**点(坐标,绘图的基本要素,包含x,y坐标)*/
          var Point=(function(x1,y1){
            var x=x1,y=y1;
            return{
              set:function(p){
                x=p.x,y=p.y;
              },
              setXY:function(x2,y2){
                x=x2;y=y2;
              },
              setX:function(x3){
                x=x3;
              },
              setY:function(y3){
                y=y3;
              },
              getX:function(){
                return x;
              },
              getY:function(){
                return y;
              }
            }
          });
          /**多角形(三角形、矩形、多边形),由多个点组成*/
          var Poly=(function(ps1){
            var ps=isNull(ps1)?new Array():ps1;
            var size=ps.length;
            return{
              set:function(ps2){
                ps=ps2;
              },
              getSize:function(){
                return size;
              },
              setPoint:function(p,i){
                if(isNull(p)&&isNaN(i)){
                  return;
                }
                ps[i]=p;
              },
              setStart:function(p1){
                if(isNull(ps)){
                  ps=new Array();
                  return ps.push(p1);
                }else{
                  ps[0]=p1;
                }
              },
              add:function(p){
                if(isNull(ps)){
                  ps=new Array();
                }
                return ps.push(p);
              },
              pop:function(){
                if(isNull(ps)){
                  return;
                }
                return ps.pop();
              },
              shift:function(){
                if(isNull(ps)){
                  return;
                }
                return ps.shift;
              },
              get:function(){
                if(isNull(ps)){
                  return null;
                }
                return ps;
              },
              draw:function(){
                cxt.beginPath();
                for(i in ps){
                  if(i==0){
                    cxt.moveTo(ps[i].getX(),ps[i].getY());
                  }else{
                    cxt.lineTo(ps[i].getX(),ps[i].getY());
                  }
                }
                cxt.closePath();
                cxt.stroke();
              }
            }
          });
          /*线条(由两个点组成,包含方向)*/
          var Line=(function(p1,p2,al){
            var start=p1,end=p2,angle=al;
            var drawLine=function(){
              cxt.beginPath();
              cxt.moveTo(p1.getX(),p1.getY());
              cxt.lineTo(p2.getX(),p2.getY());
              cxt.stroke();
            }
            //画箭头
            var drawArrow=function() {
              var vertex =ctrlConfig.vertex;
              var x1=p1.getX(),y1=p1.getY(),x2=p2.getX(),y2=p2.getY();
              var el=50,al=15;
              //计算箭头底边两个点(开始点,结束点,两边角度,箭头角度)
              vertex[0] = x1,vertex[1] = y1, vertex[6] = x2,vertex[7] = y2;
              //计算起点坐标与X轴之间的夹角角度值
              var angle = Math.atan2(y2 - y1, x2 - x1) / Math.PI * 180;
              var x = x2 - x1,y = y2 - y1,length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
              if (length < 250) {
                el/=2,al/2;
              }else if(length<500){
                el*=length/500,al*=length/500;
              }
              vertex[8] = x2 - el * Math.cos(Math.PI / 180 * (angle + al));
              vertex[9] = y2- el * Math.sin(Math.PI / 180 * (angle + al));
              vertex[4] = x2- el* Math.cos(Math.PI / 180 * (angle - al));
              vertex[5] = y2 - el * Math.sin(Math.PI / 180 * (angle - al));
              //获取另外两个顶点坐标
              x=(vertex[4]+vertex[8])/2,y=(vertex[5]+vertex[9])/2;
              vertex[2] = (vertex[4] + x) / 2;
              vertex[3] = (vertex[5] + y) / 2;
              vertex[10] = (vertex[8] +x) / 2;
              vertex[11] = (vertex[9] +y) / 2;
              //计算完成,开始绘制
              cxt.beginPath();
              cxt.moveTo(vertex[0], vertex[1]);
              cxt.lineTo(vertex[2], vertex[3]);
              cxt.lineTo(vertex[4], vertex[5]);
              cxt.lineTo(vertex[6], vertex[7]);
              cxt.lineTo(vertex[8], vertex[9]);
              cxt.lineTo(vertex[10], vertex[11]);
              cxt.closePath();
              cxt.fill();
              cxt.stroke();
            }
            return{
              setStart:function(s){
                start=s;
              },
              setEnd:function(e){
                end=e;
              },
              getStart:function(){
                return start;
              },
              getEnd:function(){
                return end;
              },
              draw:function(){
                if(angle){
                  drawArrow();
                }else{
                  drawLine();
                }
              }
            }
          });
          /**圆形(包含圆心点和半径)*/
          var Circle=(function(arr){
            //包含起始点(圆心)和结束点,以及圆半径
            var startPoint=arr.start,endPoint=arr.end,radius=arr.radius;
            /*绘制圆*/
            var drawCircle=function(){
              cxt.beginPath();
              var x=startPoint.getX();
              var y=startPoint.getY();
              if(isNull(radius)){
                radius=calculateRadius(startPoint,endPoint);
              }
              //x,y,半径,开始点,结束点,顺时针/逆时针
              cxt.arc(x,y,radius,0,Math.PI*2,false); // 绘制圆
              cxt.stroke();
            }
            //计算圆半径
            var calculateRadius=function(p1,p2){
              var width=p2.getX()-p1.getX();
              var height=p2.getY()-p1.getY();
              //如果是负数
              if(width<0||height<0){
                width=Math.abs(width);
              }
              //计算两点距离=平方根(width^2+height^2)
              c=Math.sqrt(Math.pow(width,2)+Math.pow(height,2));
              return c;
            }
            return{
              set:function(params){
                startPoint=params.start;
                endPoint=params.end;
                radius=params.radius;
              },
              setPoint:function(p1){
                p=p1;
              },
              getPoint:function(){
                return p;
              },
              setRadius:function(r1){
                radius=r1;
              },
              getRadius:function(){
                return radius;
              },
              calcRadius:calculateRadius,
              //绘制
              draw:drawCircle,
            }
          });
          /**绘制线条工具方法*/
          var drawLine=function(p){
            cxt.beginPath();
            cxt.moveTo(startPosition.getX(),startPosition.getY());
            cxt.lineTo(p.getX(),p.getY());
            cxt.stroke();
          }
          /**绘制三角形工具方法*/
          var drawTrian=function(ps){
            cxt.beginPath();
            var a=ps.get();
            cxt.moveTo(a[0].getX(),a[0].getY());
            cxt.lineTo(a[1].getX(),a[1].getY());
            cxt.lineTo(a[2].getX(),a[2].getY());
            cxt.closePath();
            cxt.stroke();
          }
          /**绘制矩形工具方法*/
          var drawRect=function(p2){
            var p=getStartPoint();
            var width=p.getX()-p2.getX();
            var height=p.getY()-p2.getY();
            cxt.beginPath();
            cxt.strokeRect(x,y,width,height);//绘制矩形
          }
          /*绘制多边形工具方法*/
          var drawpolygon=function(ps){
            if(ps.length>1){//保证只有两个坐标点才是矩形
              cxt.beginPath();
              var p=ctrlConfig.startPoint;
              var x=p.getX();
              var y=p.getY();
              cxt.moveTo(x,y);
              for(p1 in ps){
                cxt.lineTo(p1.getX(),p1.getY());
              }
              cxt.stroke();
            }
          }
          /*绘制圆角矩形工具方法*/
          var drawRoundedRect=function(x,y,width,height,radius){
            cxt.beginPath();
            cxt.moveTo(x,y+radius);
            cxt.lineTo(x,y+height-radius);
            cxt.quadraticCurveTo(x,y+height,x+radius,y+height);
            cxt.lineTo(x+width-radius,y+height);
            cxt.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
            cxt.lineTo(x+width,y+radius);
            cxt.quadraticCurveTo(x+width,y,x+width-radius,y);
            cxt.lineTo(x+radius,y);
            cxt.quadraticCurveTo(x,y,x,y+radius);
            cxt.stroke();
          }
          /*绘制圆工具方法*/
          var drawCircle=function(c){
            var p=c.getPoint();//坐标点
            var x=p.getX();
            var y=p.getY();
            var r=c.getRadius();
            cxt.beginPath();
            //x,y,半径,开始点,结束点,顺时针/逆时针
            cxt.arc(x,y,r,0,Math.PI*2,false); // 绘制圆
            cxt.stroke();
          }
          //计算圆半径工具方法
          var calculateRadius=function(p1,p2){
            var width=p2.getX()-p1.getX();
            var height=p2.getY()-p1.getY();
            //如果是负数
            if(width<0||height<0){
              width=Math.abs(width);
            }
            //计算两点距离=平方根(width^2+height^2)
            c=Math.sqrt(Math.pow(width,2)+Math.pow(height,2));
            return c;
          }
          //鼠标按键点击(首次点击确定开始坐标点,拖动鼠标不断进行图形重绘)
          var mouseDown = function(e){
            var btnNum = e.button;
            if(btnNum==0){
              console.log("选择:"+ctrlConfig.kind);
              //设置起始点
              switch(ctrlConfig.kind){
                case graphkind.pen://画笔(不松开鼠标按键一直画)
                  beginDrawing();//开始绘制
                  cxt.beginPath();
                  cxt.moveTo(e.offsetX,e.offsetY);
                  break;
                case graphkind.poly://多边形
                  var p=new Point(e.offsetX,e.offsetY);
                  if(isDrawing()){
                    getCuGraph().add(p);//添加到
                  }else{//第一次确定开始坐标
                    beginDrawing();//开始绘制
                    setStartPoint(p);
                    var poly=new Poly();
                    poly.add(p);
                    setCuGraph(poly);//设置当前绘制图形
                  }
                  break;
                case graphkind.line://线条
                case graphkind.arrow://方向
                case graphkind.trian://三角形
                case graphkind.rect://矩形
                case graphkind.parallel://平行四边形
                case graphkind.trapezoid://梯形
                  beginDrawing();//开始绘制
                  var p=new Point(e.offsetX,e.offsetY);
                  setStartPoint(p);
                  var poly=new Poly();
                  poly.add(p);
                  setCuGraph(poly);//设置当前绘制图形
                  break;
                case graphkind.circle://圆
                  console.log("确定图形绘制开始坐标点:"+e.offsetX+","+e.offsetY);//点击确定图形的开始坐标点
                  beginDrawing();//开始绘制
                  var p=new Point(e.offsetX,e.offsetY);
                  setStartPoint(p);
                  var circle= new Circle({'start':p});
                  setCuGraph(circle);
                  break;
                case ctrlConfig.cursor: //手型鼠标
                default://默认是手型鼠标,不允许绘制
              }
            }else if(btnNum==2){
              console.log("右键由于结束多边形绘制");
              if(isDrawing()){
                if(ctrlConfig.kind==graphkind.poly){
                  repaint();
                  getCuGraph().draw();
                  stopDrawing();//结束绘制
                }
              }
            }
            hideDefRM();//屏蔽浏览器默认事件
          }
          //鼠标移动(拖动,根据鼠标移动的位置不断重绘图形)
          var mouseMove = function(e){
            if(isDrawing()&&hasStartPoint()){//检查是否开始绘制,检查是否有开始坐标点
              //画笔不需要重绘
              if(ctrlConfig.kind>1){
                repaint();//重绘
              }
              var p=setCuPointXY(e.offsetX,e.offsetY,0);//设置共享的临时坐标点,用于防止重复创建对象
              switch(ctrlConfig.kind){
                case graphkind.pen://画笔(一直画)
                  cxt.lineTo(e.offsetX,e.offsetY);
                  cxt.stroke();
                  break;
                case graphkind.poly://多边形
                  var poly=getCuGraph(poly);
                  var size=poly.getSize();
                  poly.setPoint(p,(size-1));
                  poly.draw();
                  break;
                case graphkind.line://线条
                  var line=new Line(getStartPoint(),p,false);
                  ctrlConfig.cuGraph=line;
                  line.draw();
                  break;
                case graphkind.arrow://方向
                  var line=new Line(getStartPoint(),p,true);
                  ctrlConfig.cuGraph=line;
                  line.draw();
                  break;
                case graphkind.trian://三角形
                  var lu=getStartPoint();
                  var x2=p.getX();
                  var x1=lu.getX();
                  //三角形左边的点坐标计算方法:(x1-(x2-x1),y2)
                  var x3=x1-(x2-x1);
                  var l=setCuPointXY(x3,p.getY(),1);//设置共享的临时坐标点,用于防止重复创建对象
                  var poly=getCuGraph();//获取当前图形
                  poly.set([lu,p,l]);
                  poly.draw();//即时绘制
                  break;
                case graphkind.parallel://平行四边形
                  var lu=getStartPoint();
                  var x3=p.getX();
                  var x1=lu.getX();
                  //平行四边形两个未知坐标点计算方法:(x1-(x3-x1),y3),(x1+(x3-x1),y1)
                  var x2=x3+(x3-x1);
                  var x4=x1-(x3-x1);
                  var ld=setCuPointXY(x2,lu.getY(),1);//设置共享的临时坐标点,用于防止重复创建对象
                  var ru=setCuPointXY(x4,p.getY(),2);//设置共享的临时坐标点,用于防止重复创建对象
                  var poly=getCuGraph();//获取当前图形
                  poly.set([lu,ru,p,ld]);
                  poly.draw();//即时绘制
                  break;
                case graphkind.trapezoid://梯形
                  var lu=getStartPoint();
                  var x3=p.getX();
                  var x1=lu.getX();
                  //梯形两个未知坐标点计算方法:(x3-(x3-x1)/2,y1),(x1-(x3-x1)/2,y3)
                  var x2=x3-(x3-x1)/2;
                  var x4=x1-(x3-x1)/2;
                  var ld=setCuPointXY(x2,lu.getY(),1);
                  var ru=setCuPointXY(x4,p.getY(),2);
                  var poly=getCuGraph();
                  poly.set([lu,ru,p,ld]);
                  poly.draw();
                  break;
                case graphkind.rect://矩形
                  var lu=getStartPoint();
                  //矩形右上角和左上角坐标计算方法
                  var ld=setCuPointXY(lu.getX(),p.getY(),1);
                  var ru=setCuPointXY(p.getX(),lu.getY(),2);
                  var poly=getCuGraph();
                  poly.set([lu,ru,p,ld]);
                  poly.draw();
                  break;
                case graphkind.circle://圆
                  var circle=getCuGraph();//获取当前图形
                  circle.set({'start':getStartPoint(),'end':p});
                  circle.draw();//即时绘制
                  break;
              }
            }
          }
          //鼠标按键松开
          var mouseUp = function(e){
            if(isDrawing()){
              //console.log("松开鼠标按键:"+e.offsetX+","+e.offsetY);
              //画笔不需要重绘
              if(ctrlConfig.kind>1){
                repaint();
                getCuGraph().draw();
              }
              if(ctrlConfig.kind!=graphkind.poly){//多边形绘制鼠标按键松开不结束绘制,多边形只有右键点击才能结束绘制
                stopDrawing();//结束绘制
              }
            }
          }
          //鼠标移出
          var mouseOut = function(e){
            console.log("鼠标移出绘制区域"+e.offsetX+","+e.offsetY);
            if(isDrawing()){
              console.log("停止绘制");
              if(ctrlConfig.kind>1){
                repaint();
                getCuGraph().draw();
              }
              stopDrawing();//停止绘制
            }
          }
          return{
            isNull:isNull,
            getDom:getDom,
            clear:function(){
              stopDrawing();//停止绘制
              repaint();
            },
            /**初始化*/
            init:function(params){
              cbtCanvas=getDom(params.id);
              //浏览器是否支持Canvas
              if (cbtCanvas.getContext){
                /**绘图对象*/
                cxt=cbtCanvas.getContext("2d");
                cbtCanvas.onmousedown = mouseDown;
                cbtCanvas.onmouseup = mouseUp;
                cbtCanvas.onmousemove = mouseMove;
                cbtCanvas.onmouseout = mouseOut;
                resetStyle();//载入样式
                return true;
              }else{
                return false;
              }
            },
            /**设置背景图片*/
            setBgPic:loadPicture,
            /**选择图形类型*/
            begin:function(k){
              console.log("选择绘制图形:"+k);
              if(isNaN(k)){//如果不是数字,先转换为对应字符
                ctrlConfig.kind=kind[k];
              }else{
                ctrlConfig.kind=k;
              }
              switchCorser(true);//切换鼠标样式
            },
            /*手型,并停止绘图*/
            hand:function(){
              ctrlConfig.kind=0;
              stopDrawing();//停止绘制
              switchCorser(false);//切换鼠标样式
            }
          }
        })

    三、使用方式

    1、图形类型

    0:鼠标,1:画笔,2:线条,3:三角形,4:矩形,5:多边形,6:圆形,21:箭头,41:平行四边形,42:梯形

    var graphkind={'cursor':0,'pen':1,'line':2,'trian':3,'rect':4,'poly':5,'circle':6,'arrow':21,'parallel':41,'trapezoid':42};

    2、初始化以及使用背景图片和画笔选择

    var drawUtil=new DrawingTools();
    //初始化,(如果浏览器不支持H5,会初始化失败,返回false)
    if(drawUtil.init({'id':'calibrationCanvas'})){
    //加载图片
    var imgsrc='图片地址';
    if(!drawUtil.isNull(imgsrc)){
      drawUtil.setBgPic(imgsrc,true);//设置背景图片(异步加载图片)
    }
    }
    drawUtil.begin(1);//选择画笔

    2、绘制箭头

    drawUtil.begin(21);

    总结

    以上所述是小编给大家介绍的原生JS使用Canvas实现拖拽式绘图功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对北冥有鱼网站的支持!
    如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

    您可能感兴趣的文章:

    • JS实现移动端触屏拖拽功能
    • JS实现的文件拖拽上传功能示例
    • 原生js实现拖拽功能基本思路详解
    • js实现控制文件拖拽并获取拖拽内容功能
    • JS实现基于拖拽改变物体大小的方法
    • AngularJS实现的简单拖拽功能示例
    • 使用javaScript实现鼠标拖拽事件
    • Java实现拖拽文件上传dropzone.js的简单使用示例代码
    • 前端页面文件拖拽上传模块js代码示例
    • 详解plotly.js 绘图库入门使用教程
    • JavaScript基础——使用Canvas绘图
    • JavaScript 绘图代码
    • 用JavaScript绘图 ——JS2D函数集
    • 用js绘图

    广而告之:
    热门推荐:
    php和editplus正则表达式去除空白行

    去除字符串内部的空行: 复制代码 代码如下: $str = preg_replace("/(\s*?\r?\n\s*?)+/","\n",$str); 去除全部的空行,包括内部和头尾: 复制代码 代码如下: $str = preg_replace('/($\s*$)|(^\s*^)/m', '',$str); editplus中替换空白行的正则表达式: 正则表···

    解决Vue页面固定滚动位置的处理办法

    最近做项目遇到一个问题,就是Vue滚动不固定,网上找了一些资料,说下 vue 固定滚动位置的处理办法. 问题描述: 通常见于 列表页List -> 详情页Detail 的情况, 从列表的某一项x 进入到详情页, 再返回的时候, 希望列表的位置固定在x, 而不是回到顶部了. vue-router 里面是有···

    Node.js pipe实现源码解析

    从前面两篇文章,我们了解到。想要把 Readable 的数据写到 Writable,就必须先手动的将数据读入内存,然后写入 Writable。换句话说,每次传递数据时,都需要写如下的模板代码 readable.on('readable', (err) => { if(err) throw err writable.write(readable.read()) })···

    PHP strtok()函数的优点分析

    其优点是: 1、可以一次定义多个分隔符。函数在执行时,是按单个分隔符来切割,而不是按整个分隔符,而explode则是按整个分隔串来切割的。正因此,explode可以用中文切割,而strtok则不行,会乱码。 2、在使用while或for配合strtok()遍历时,可以随时更换分隔符,也可以···

    Dedecms升级到5.5自动生成首页失效的修改方法

     最近,很多网友反映跟烈火网反映DedeCMS5.3升级到5.5以后,或者打了9.12发布的补丁后,出现了发表文章后主页不自动更新的问题,这里我给大家介绍一种解决办法:     在网站的安装目录里找到找到 /dede/task_do.php这个文件     在第95行$pv = new PartVie···

    织梦php主动推送完整实例(单篇推送版本)

    打开article_add.php文件,查找如下代码 -------     if($artUrl=='')     {         $artUrl = $cfg_phpurl."/view.php?aid=$id";     }     ClearMyAddon($id, $tit···

    javascript函数的节流[throttle]与防抖[debounce]

    防抖和节流 窗口的resize、scroll,输入框内容校验等操作时,如果这些操作处理函数较为复杂或页面频繁重渲染等操作时,如果事件触发的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少触发的频率,同···

    浅析CSS里的BFC和IFC的用法

    前言 之前一直听到有人提到 CSS里的BFC,正巧在 IFE的练习里遇到了外边距折叠的问题,所以正好弄清楚BFC的机制。 (参考来源 见文末的 Reference) 一 什么是 BFC 和之前所有博文一样,还是先从What的角度开始介绍,由浅入深的理解BFC。 所谓的 Formatting context(格式化上下文)···

    深入研究React中setState源码

    React作为一门前端框架,虽然只是focus在MVVM中的View部分,但还是实现了View和model的绑定。修改数据的同时,可以实现View的刷新。这大大简化了我们的逻辑,只用关心数据流的变化,同时减少了代码量,使得后期维护也更加方便。这个特性则要归功于setState()方法。React中利用···

    webpack公共组件引用路径简化小技巧

    日常开发中,我们会常常把一些功能提取出来,包装成一个公共模块或者组件,供不同地方使用,但是随着项目不断变大,项目目录不断变深,我们引用公共组件的路径越来越长! 例如:引用一个公共模块 import Menu from '../../../../../components/Menu'; // 这里路径太深,很容易···