解决方案 »

  1.   

    晒个代码顶一下! 欢迎帖子回复或qq交流 114-021-5489。<!doctype html>
    <html>
    <head>
    <title>javascript面向对象特性实现连线应用</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <style>
    *{padding:0;margin:0;font: 18px 'Microsoft Yahei';}
    .matchByLineBox{margin:50px;width: 500px;height: 250px;border: 1px solid red;position:relative;float: left;}
    .matchSide{border: 1px solid #333;position: absolute;}
    .mlBoxCol .matchSide{width:200px;min-height: 200px;top: 5px; }
    .mlBoxCol .matchSideQue{left: 5px;}
    .mlBoxCol .matchSideAns{right: 5px;}
    .matchOne{border: 1px solid #ccc;margin: 2px;min-width: 50px;min-height: 50px;}
    </style>
    <script src="http://cdn.bootcss.com/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript">
    //适配移动端
    AdaptUtil={
    touchAble:'ontouchstart' in window,
    eventNameInit:function(){
    mousedown =this.touchAble ? "touchstart ":"mousedown ";
    mouseup =this.touchAble ? "touchend ":"mouseup ";
    mousemove =this.touchAble ? "touchmove ":"mousemove ";
    mouseout=this.touchAble ? "touchcancel ":"mouseout ";
    },
    //转成可以直接获取坐标的事件对象
    getAdaptEvt:function(e,index){//jqEvent,触点索引
    if(this.touchAble){
    index=index==undefined ? 0 :index;
    e=e.originalEvent.changedTouches[index];
    }
    return e;
    }
    } /***********************************以上PC移动端兼容处理*****************************/
    function MatchByLine(cvsBox){//构造函数
    this.cvsBox =cvsBox; 
    this.cvs=undefined;
    this.begin=undefined;
    this.beginOne=undefined;
    this.beginIsQue=false;
    } MatchByLine.prototype={//类方法
    init:function(){
    var self=this;
    var cvsBox=self.cvsBox;
    self.cvs=document.createElement("canvas");
    cvsBox.prepend(self.cvs);
    cvsBox.on(mousedown,function (e) {
    var pointEvt=AdaptUtil.getAdaptEvt(e);
    var ot=$(pointEvt.target);
    if(! ot.hasClass('matchOne') && ot.parents(".matchOne").length==0) return false;
    self.begin=self.getEvtCoorInMatchCvs(pointEvt);
    self.beginOne=ot.hasClass('matchOne') ? ot :ot.parents(".matchOne");//起点的matchOne
    self.beginIsQue=self.beginOne.parents(".matchSide").hasClass('matchSideQue');
    return false;
    }).on(mousemove,function (e) {
    var begin=self.begin;
    var beginOne=self.beginOne;
    var beginIsQue=self.beginIsQue;
    if(begin==undefined) return false; 
    var pointEvt=AdaptUtil.getAdaptEvt(e);
    var clientX=pointEvt.clientX,clientY=pointEvt.clientY;
    end=self.getEvtCoorInMatchCvs(pointEvt);
    var endOne=self.getOverMatchOne(clientX,clientY);
    if(endOne==null){//落点不在matchOne内
    self.drawMatchLine(begin,end);
    return false; 
    }
    var endIsQue=endOne.parents(".matchSide").hasClass('matchSideQue');
    if(beginIsQue ^ endIsQue){//起落点在不同侧
    var matchOne_que,matchOne_ans;
    if(beginIsQue){//判断起落点分别在问题侧还是答案侧
    matchOne_que=beginOne;
    matchOne_ans=endOne;
    }else{
    matchOne_que=endOne;
    matchOne_ans=beginOne;
    }
    matchOne_que.attr('ans', matchOne_ans.text());
    self.drawMatchLine();
    self.begin=undefined;
    }else{//起点和落点在同一侧 无效 答案不更新
    self.drawMatchLine(begin,end);
    }
    }).on(mouseup,function (e) {
    self.begin=undefined;
    self.drawMatchLine();
    })
    },
    getOverMatchOne:function(clientX,clientY){
    var one=null;
    var cvsBox=this.cvsBox;
    var mos=cvsBox.find('.matchOne');
    mos.each(function(i){
    var cr=mos.eq(i)[0].getBoundingClientRect();
    var minLeft=cr.left,minTop=cr.top,width=cr.width,height=cr.height;
    var maxLeft=minLeft+width,maxTop=minTop+height;
    if(clientX>= minLeft && clientX<=maxLeft && clientY>=minTop && clientY<=maxTop){
    one=mos.eq(i);
    return false;
    }
    })
    return one;
    },
    drawLine :function(begin,end){
    var ctx=this.cvs.getContext('2d');
    ctx.beginPath();
    ctx.moveTo(begin.x,begin.y);
    ctx.lineTo(end.x,end.y);
    ctx.strokeStyle="green";
    ctx.lineWidth = 2;  
    ctx.stroke();
    },
    drawMatchLine:function(begin,end){
    var self=this;
    var cvsBox= self.cvsBox;
    var cvs = self.cvs;
    cvs.width=cvsBox.width(),cvs.height=cvsBox.height();
    var ctx=cvs.getContext('2d');
    ctx.clearRect(0,0,cvs.width,cvs.height);
    var ques=cvsBox.find('.matchSideQue .matchOne');
    var ans=cvsBox.find('.matchSideAns .matchOne');
    for (var i = 0; i < ques.length; i++) {
    var queOne=ques.eq(i);
    var ansText=queOne.attr('ans');
    if(typeof ansText=="undefined") continue;
    for(var j=0;j<ans.length;j++){
    var ansOne=ans.eq(j);
    if(ansText==ansOne.text()){
    var oldBegin=self.getMatchOneJunctionCoor (queOne,"matchByLineBox");
    var oldEnd=self.getMatchOneJunctionCoor (ansOne,"matchByLineBox");
    self.drawLine(oldBegin,oldEnd);
    }
    }
    }
    if(typeof begin!="undefined") self.drawLine(begin,end);//up时cvs重绘不执行此句
    },
    getEvtCoorInMatchCvs:function(pe) {
    var pageX=pe.pageX,pageY=pe.pageY;
    var offset=this.getOffsetInParent(this.cvsBox[0],document.body);
    var x=pageX-offset.left,y=pageY-offset.top;
    return {x:x,y:y};
    },
    getOffsetInParent:function(ele,parent){//js ele
    var left=0,top=0;
    while(ele && ele!=parent){
    left+=ele.offsetLeft;
    top+=ele.offsetTop;
    ele=ele.offsetParent;
    }
    return {left:left,top:top};
    },
    getMatchOneJunctionCoor:function(one) {
    var x=0,y=one.height()/2;
    if(one.parent().hasClass('matchSideQue')){
    x=one.width();
    }
    var offset=this.getOffsetInParent(one[0],this.cvsBox[0]);
    x+=offset.left,y+=offset.top;
    return {x:x,y:y};
    }
    }//End MatchByLine.prototype  /*********************************以上为MatchByLine类*******************************/
    AdaptUtil.eventNameInit();
    $(function() {
    var mblBoxs=$(".matchByLineBox");
    mblArr=[];//全局 存储所有mbl实例
    mblBoxs.each(function(x){
    var mbl=new MatchByLine(mblBoxs.eq(x));
    mbl.init();
    mblArr.push(mbl);
    }); addOneMatchLineAns({"id":1,"answer":"B"});
    addOneMatchLineAns({"id":4,"answer":"D"});
    }) //答案设置接口 如addOneMatchLineAns({id:2,answer:"A"})
    function addOneMatchLineAns(ansOneObj){
    var ansText=ansOneObj.answer;
    var queId=ansOneObj.id;
    var matchOne=$(".matchOne[queId="+queId+"]");
    matchOne.attr("ans",ansText);
    var cvsBox=matchOne.parents(".matchByLineBox");
    var  mblIndex=$(".matchByLineBox").index(cvsBox);
    for(var x in mblArr){
    if($(".matchByLineBox").index(mblArr[x].cvsBox)==mblIndex){
    mblArr[x].drawMatchLine();//找到dom索引相同的实例对象,调用划线方法
    }
    }
    }</script>
    </head><body>
    <div class="matchByLineBox mlBoxCol">
    <div class="matchSide matchSideQue">
    <div class="matchOne" queId="1">甲</div>
    <div class="matchOne" queId="2">乙</div>
    </div>
    <div class="matchSide matchSideAns">
    <div class="matchOne">A</div>
    <div class="matchOne">B</div>
    </div>
    </div>
    <div class="matchByLineBox mlBoxCol">
    <div class="matchSide matchSideQue">
    <div class="matchOne" queId="3">丙</div>
    <div class="matchOne" queId="4">丁</div>
    </div>
    <div class="matchSide matchSideAns">
    <div class="matchOne">C</div>
    <div class="matchOne">D</div>
    </div>
    </div>
    </body>
    </html>
      

  2.   

    javascript设计模式推荐楼主看这本书