计算Vuejs中DOM元素之间距离的最佳方法是什么?

时间:2016-12-06 11:18:35

标签: javascript vue.js vuejs2

我正在构建一个从数据生成pdf文件的工具,我需要构建两种格式:105mm * 148mm和105mm * 210mm。所以我得到了我的整个文档,现在是我插入分页符的时候了。我用一个简单的类来做:

.page-break { display: block; page-break-before: always; }

现在我必须将此类插入到我的v-for循环中。所以一个基本的想法是计算一个区间,就像每个索引是6的倍数,我插入一个。但这不是最好的方法,我想在内容超过90毫米时插入一个断点。

为了做到这一点,我想计算2个中断之间的距离,如果距离接近90毫米,则插入一个新的中断。但是,我找不到访问动态DOM元素的方法......

所以问题很简单:如何计算这个距离?或者如果有更好的方法来实现我的目标,我还能改进什么?

2 个答案:

答案 0 :(得分:3)

我相信你在每个v-for中添加一个div / component,你可以为每个div添加一个唯一的id。现在,下面的方法可以为px提供一个div的高度,您可以通过某种方式将px转换为mm

如果您使用jquery,则可以

$('#nthDiv').height();

如果没有,您可以执行以下操作:

inner height

document.getElementById('#nthDiv').clientHeight;

outer height

document.getElementById('#nthDiv').offsetHeight; 

如果您有以下代码:

<div v-for="(item, index) in items" :class="{'page-break': isBreakNeeded(index)}" :id="index + 'thDiv'">
   ///Your code
</div>

您需要添加以下方法:

isBreakNeeded (index) {       
   var height = 0
   do {
      index -= 1;
      height += document.getElementById('#' + index + 'thDiv').offsetHeight; 
      } while (index >= 0 || pageBreakAdded[index] == true)
      if(height > threshold){
         pageBreakAdded[index] = true
         return  true
      }
      else{
         return  false
      }
}

您还需要在vue元素的data属性中添加以下哈希值,这将跟踪您添加了分页符的索引:

pageBreakAdded: {}

答案 1 :(得分:2)

所以,我尝试了这种方法:

  1. 在我的循环模板(page-break
  2. 中插入div v-for each data text element
  3. 在渲染后选择所有page-break
  4. 使用getBoundingClientRect()进行计算
    1. 循环选择
    2. 获取当前休息与下一个休息之间的距离
    3. 如果超出可接受范围,请将其从DOM中删除。
  5. 这种方法有效,但非常难看,计算好的范围非常困难,而且价格非常昂贵!有了一个小数据集,没关系,但是整本书太长了......

    这是第一次尝试(使用Vue模板)

    <template>
      <div class="content">
        <div class="pages">
          <div class="page-footer">
            <div class="page-break"></div>
          </div>
    
          <div class="dynamic">
            <div v-for="(entry, index) in conv" class="row">
              <div v-if="entry.msgs[0].value === 'break'">
                <span class="date">{{entry.msgs[0].metadate}}</span>
              </div>
    
              <div v-else>
                <span class="author">{{ entry.user }}</span>
                <span class="hour">{{ entry.msgs[0].metahour }}</span>
                <div class="phrases">
                  <span v-for="msg in entry.msgs">
                    {{ msg.value }}
                  </span>
                </div>
              </div>
    
              <div class="page-footer" :data-base="index">
                <span class="page-number" :data-base="index">{{ pageNumberFor(index) }}</span>
                <div class="page-break"></div>
              </div>
            </div>
          </div>
    
          <div class="page-footer" data-base="end">
            <span class="page-number" data-base="end">{{ pageNumberFor('end') }}</span>
            <div class="page-break"></div>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    
    import und from 'underscore'
    
    export default {
      name: "Data",
    
      data () {
        return {
          conv: null,
          cleaned: false,
          pageNumbers: {}
        }
      },
    
      computed: {
        mmScale: () => 0.264583333,
        heightBreak: () => 210
      },
    
      mounted () {
        this.$http.get('static/data_sorted_backup.json').then(
        // this.$http.get('static/data_sorted.json').then(
          (response) => {
            this.conv = this.groupBy(response.data)
          },
          (response) => {
            console.log('error');
          }
        )
    
    
      },
    
      updated () {
        console.log('updated');
        if(!this.cleaned) this.cleanPageBreak()
      },
    
      methods: {
        groupBy (json) {
          let result = []
          result.push(json[0])
    
          let punc = new RegExp(/[\?\.\!\;\(\)]?$/, 'ig')
    
          for (var i = 1; i < json.length; i++) {
            let val = json[i].msgs[0].value
            val = val.charAt(0).toUpperCase() + val.slice(1);
            if( punc.test(val) === false ) val += '.'
            json[i].msgs[0].value = val
    
            let len = result[result.length -1].msgs.length
            // if it's not the same day
    
            let origin = result[result.length -1].msgs[len - 1].metadate
            let new_entry = json[i].msgs[0].metadate
            // console.log(i, origin, new_entry);
            if( origin !== new_entry ){
              result.push({
                msgs: [{
                  value:"break",
                  metadate: json[i].msgs[0].metadate
                }]
              })
              i--
              continue;
            }
    
            // if the previous author is the same
            if(result[result.length -1].user === json[i].user){
              result[result.length -1].msgs.push({
                value: json[i].msgs[0].value,
                metadate: json[i].msgs[0].metadate,
                metahour: json[i].msgs[0].metahour
              })
    
            }else{
              result.push(json[i])
            }
          }
    
          return result
        },
    
        cleanPageBreak () {
          console.log('cleanPageBreak');
          let breaks = this.$el.querySelectorAll('.page-footer')
          let distance
          let enough
          let previousTop = breaks[0].getBoundingClientRect().top
    
          let seuil = this.heightBreak * 0.85
    
          console.log(breaks.length, seuil);
    
          for (let i = 1; i < breaks.length; ++i) {
            console.log(i);
            distance = (breaks[i].getBoundingClientRect().top - previousTop) * this.mmScale
    
            enough = distance < this.heightBreak && distance >= seuil
    
    
            if (enough) {
              previousTop = breaks[i].getBoundingClientRect().top
            } else if(i != breaks.length -1) {
              breaks[i].remove()
            }
          }
          this.cleaned = true
          this.mapNumbers()
        },
    
        mapNumbers () {
          console.log('mapNumbers');
          let numbers = Array.from(this.$el.querySelectorAll('.page-number'))
    
          numbers.map( (elem, index) => {
            this.pageNumbers[elem.dataset.base] = {}
            this.pageNumbers[elem.dataset.base].index = index + 1
          })
        },
    
        pageNumberFor (index) {
          if(this.pageNumbers[index]) return this.pageNumbers[index].index
          return 0
        }
      }
    }
    </script>
    
    <style lang="scss">
    @import url('https://fonts.googleapis.com/css?family=Abel|Abhaya+Libre');
    
    
    .page-footer{
      position: relative;
      margin: 12mm 0;
      // border: 1px dotted black;
    
      .page-break   {
        display: block;
        page-break-before: always;
      }
    
      .page-number {
        position: absolute;
        left: 50%;
        transform: translate(-50%, 0);
        top: -28mm;
      }
    }
    
    .content {
      padding: 0 16mm 0 10mm;
      font-family: 'Abhaya Libre', serif;
    
      .pages{
        position: relative;
      }
    }
    .row {
      margin: 0;
      font-size: 0;
    
      span{
        font-size: 13px;
      }
      span:first-letter {
        text-transform: uppercase;
      }
    
      .date, .hour {
        font-family: 'Abel', sans-serif;
      }
      .date {
        font-size: 15px;
        text-align: center;
        display: block;
        padding-top: 10mm;
        padding-bottom: 2mm;
      }
      .author{
        display: block;
        text-transform: uppercase;
        text-align: center;
      }
      .hour {
        margin-bottom: 3mm;
        margin-top: -2px;
        display: block;
        text-align: center;
        font-size: 9px;
      }
      .phrases{
        text-indent:5mm;
      }
    }
    
    .row + .row {
      margin-top: 5mm;
    }
    </style>