相似world中批註在側邊欄瀏覽功能的js實現

初入前端,最近在使用word時發現有個批註功能,就想的如何用代碼去實現一下css

1、大概需求以下:

1.頁面總體分爲左中右兩部分,中間爲正文內容區域,右右兩側爲註釋瀏覽區域
2.右側展現的註釋內容必須與所需註釋詞彙在一條線上
3.初始時只顯示兩行內容,點擊時展開所有
4.若是兩個被註釋的詞距離太近,註釋部分要求依次排序html

2、預設解決方案

1.在註釋內容外側添加一個div,利用div的min-height屬性控制註釋的位置
2.利用position: absolute絕對定位,動態的生成和改變註釋的位置前端

3、實現過程

在實現上述兩種方法的過程當中發現,第一種方案在數據量龐大的狀況下,會出現bug,頁面會奔潰,果斷放棄了,選擇了第二種方式實現jquery

1.常量部分:

1> args--------->當前文章內容中有註釋的詞集合
2> notes-------->從庫中獲取到的註釋文本集合
3> rightWrap---->右側部分註釋區域對象
4> leftWrap----->左側部分註釋區域對象數據庫

2.方法部分

1> setSite()------------------------------>初始界面加載時肯定註釋的位置
2> resetTop(elem, type)------------------->在點擊時從新設置全部註釋的位置
elem:當前被點擊的對象
type:(open/close)所有展開或部分展現
3> bindClick(elem, type, selector, fn)---->綁定事件函數
elem:綁定事件的元素
type:綁定的事件類型,例如(click)
selector:動態添加到elem中的元素
fn:綁定事件執行後回調方法app

3.總體代碼

1> index.html部分代碼ide

<div class="wrap">
    <aside class="left"></aside>
    <article class="center">
        <h3>人世</h3>
        <br />
        <p>使其停下來</p>
        <p>使光影、蜉蝣</p>
        <p><b class="special-0 nleft">衆生</b>的所向是什麼</p>
        <p>尤以靜止方可得出</p>
        <p>我不作空明的闡述</p>
        <p>我是凡人,且一直落在凡塵裏</p>
        <p>使雲霞似錦吧</p>
        <p>若產出時間的黃金</p>
        <p>時間的<b class="special-1">黃金</b>只能在一顆內心</p>
        <p>播種,<b class="special-2">萌發</b>,成爲照耀</p>
        <p>內斂的照耀比及月亮</p>
        <p>咱們需作輝光的同謀人</p>
        <p>咱們依舊不能成爲閃電或是驚雷</p>
        <p>咱們只是平凡的形形色色</p>
        <p>爲全部悸動歡呼的應該是另外一羣人</p>
        <p>那些卑微的怯懦的都給我</p>
        <p>我隱在暗處說——</p>
        <p>「這很好!」,是的,你注視我說——</p>
        <p>「你很好!」</p>
        <p>還有可使其墮落下去使其淪陷下去的嗎</p>
        <p>光影、<b class="special-3">蜉蝣</b>、我和你</p>
        <p>和岸邊無風也要搖盪的蘆葦</p>
        <p>和彷佛永不休止的蟬鳴</p>
        <p>和流水</p>
    </article>
    <aside class="right"></aside>
</div>

2> index.css部分代碼函數

.wrap {
    display: flex;
    position: relative;
    width: 100%;
}
article.center {
    flex: 1;
    text-align: justify;
    padding: 20px;
    border-right: 1px solid #ddd;
    border-left: 1px solid #ddd;
}
article.center p {
    line-height: 24px;
}
article.center p b {
    color: red;
}
aside.left, aside.right {
    width: 300px;
    padding: 20px 0;
}
.wrap aside mark {
    background-color: #fff;
    color: #afafaf;
    padding: 0 20px;
    position: absolute; 
    top: 0;
    height: 44px;
    overflow: hidden;
    line-height: 20px;
    font-size: 12px;
    text-align: justify;
    cursor: pointer;
    width: 260px;
}

3> index.js部分代碼flex

;
(function() {
    
//  構造函數
    function View(elem, notes, rightWrap, leftWrap) {
        this.rightWrap = rightWrap;
        this.leftWrap = leftWrap;
        this.args = typeof elem === 'object' ? elem : document.getElementById(elem);
        this.notes = notes === undefined ? [] : notes;
        
        this.init();
    }
    
//  原型
    View.prototype = {
        constructor: View,
        
        init: function() {
            var self = this;
            self.setSite();
            self.bindClick(document.body, 'click', 'mark', function (e) {
                var target = e.target;
                if(this.style.height) {
                    this.style.height = '';
                      self.resetTop(this, 'close');
                    return;
                } else {
                    this.style.height = this.scrollHeight +'px';
                      self.resetTop(this, 'open');
                }
            });
        },
        
//      設定初始高度
        setSite: function() {
            for(let i = 0; i < this.args.length; i++) {
//               默認新建的批註距離頂部的高度
                 var swdTop = 0;
                 var addMark = '';
                 
//              計算當前批註的高度是否被覆蓋,若是被覆蓋,進行處理
                if(i > 0) {
                       if(this.args[i].offsetTop - this.args[i-1].offsetTop > $('.note-' + (i-1)).height()) {
                           swdTop = this.args[i].offsetTop - 2 + 'px';
                       } else {
                           swdTop = this.args[i-1].offsetTop + $('.note-' + (i-1)).height() - 2 + 'px';
                       }
                   } else {
                       swdTop = this.args[i].offsetTop - 2 + 'px';
                   }
                 
                 if(this.notes.length > 0) {
                     addMark = '<mark class="note-' + i + '" style="top:' + swdTop + '">'+ this.args[i].innerHTML     +':' + this.notes[i] + '</mark>';
                 } else {
                     addMark = '';
                 }
                 
//                 將獲得的新標籤動態添加到容器中
                   if(this.args[i].classList.length > 1 && this.args[i].classList[1] === 'nleft' && this.leftWrap !== undefined) {
                     this.leftWrap.append(addMark);
                 } else {
                     this.rightWrap.append(addMark);
                 }
             }
        },
        
//      從新設置元素高度
        resetTop: function(elem, type) {
            let index = parseInt(elem.className.substr(elem.className.indexOf('-')+1));
            for(; index < this.args.length-1; index++) {
                var swdNewTop = 0;
                var addTop = [];
                if(this.args[index+1].offsetTop - this.args[index].offsetTop > $('.' + elem.className).height()) {
                    console.log('咱們不須要執行任何東西了')
                    return
                } else {
                    if(type === 'open') {
                        swdNewTop = this.args[index].offsetTop + $('.' + elem.className).height() + 8 + 'px';
                        addTop[index+1] = swdNewTop;
                    } else {
                        swdNewTop = this.args[index].offsetTop + $('.' +  elem.className).height() + 'px';
                    }
                    $('.note-' + (index+1)).attr('style', 'top:' + swdNewTop);
                    return
                }
            }
        },
        
//      綁定元素點擊事件
        bindClick: function(elem, type, selector, fn) {
             if(fn === null) {
                 fn = selector;
                 selector = null;
             }
             elem.addEventListener(type, function(e) {
                 var target = e.target;
                 if(selector) {
                     target = e.target;
                     if(target.matches(selector)) {
                         fn.call(target, e);
                     }
                 } else {
                     fn(e);
                 }
             })
         }
    }
    
//  對外公開方法
    window.View = View;
})();

4.經過擴展方法將拖拽方法擴展到jquery的一個實例方法

(function($) {
  $.fn.extend({
    viewDocument: function(notes, rightWrap, leftWrap) {
      new View(this, notes, rightWrap, leftWrap);
      //  爲了保證jQuery全部的方法可以實現鏈式訪問,每一個方法的最後必須返回this,即返回jquery的實例
      return  this;
    }
  })
})(jQuery);

5.在主界面上的調用方法

//  此內容從數據庫中獲取,這裏只是舉個例子
let notes = [
         '某些腦殘們如今農村你如今,每次, 很快就恢復九分褲空間發揮科技的護膚開始開好房間快點恢復快接啊漢蘭達!',
         '夢想決定了開始,沒拿到,啥的,明年初,茉香奶茶, 空間打開手機上看到空間發揮的機會福克斯杜鵑花開始瘋狂開幾號放假回家看到好看接電話時刻,會盡快的釋放開好房間大客戶',
         '沒你聰明,在哪吃沒寫呢不出毛病都說了卡刷卡機打儘快打款收到啦囊括了速度很快啦可垃圾袋',
         '歐文一二惡牛肉回覆可見回覆可見空間十分開始。很快地恢復快速回復確定是客戶反饋的金鳳凰,等會看是否考覈得分健康的首付款'
     ];
     
//  獲取註釋所在的容器
let rightWrap = $('aside.right');
let leftWrap = $('aside.left');
$('.center b').viewDocument(notes, rightWrap, leftWrap);

4、總結

以上寫的時間比較急,代碼很粗糙,有相似功能的大神們有好的建議或者想法多多留言與分享,謝謝
先就這些吧,後續再繼續改進和優化
相關文章
相關標籤/搜索