2016-12-06 2 views
11

Я создаю инструмент для создания PDF-файла из данных, и мне нужно построить в двух форматах: 105 мм * 148 мм и 105 мм * 210 мм. Поэтому я получил весь свой документ, и теперь мне пора вставлять разрывы страниц. Я делаю это с простым классом:Каков наилучший способ вычисления расстояния между элементами DOM в Vuejs?

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

Теперь мне нужно вставить этот класс в мой цикл v-for. Итак, основная идея состоит в том, чтобы вычислить интервал, так как каждый индекс является кратным 6, я вставляю один. Но это не лучший способ сделать это, я хочу вставить разрыв, когда содержание превышает 90 мм.

Для этого я хотел вычислить расстояние между двумя разрывами и вставить новый, если расстояние около 90 мм. Но я не могу найти способ доступа к моим динамическим элементам DOM ...

Итак, вопрос прост: как вычислить это расстояние? Или, если есть лучший способ достичь моей цели, что я могу улучшить?

+0

возможно добавить код. –

+0

@ hardik-satasiya сделано –

ответ

3

Я считаю, что вы добавляете div/component в каждом v-for, и вы можете добавить уникальный идентификатор для каждого div. Теперь ниже методы могут дать вам высоту одного div в px, и у вас будет какой-то способ конвертировать 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 
     } 
} 

Вам нужно добавить следующий хэш, а в атрибуте данных вашего вю элемента, который будет держать Колея на какие индексы вы добавили разрыв страницы:

pageBreakAdded: {} 
+0

Хорошая идея с 'v-if'condition, возможно, это будет быстрее. –

+0

@GeorgeAbitbol Если вы находите этот подход полезным, вы видите здесь какие-либо проблемы? – Saurabh

+0

@Saurabh, Кажется, вы мастер vue.js. Мне нужна ваша помощь. Смотрите здесь: http://stackoverflow.com/questions/41843823/how-to-display-button-link-with-vue-js –

2

Итак, я попробовал этот подход:

  1. вставить page-break внутри моего шаблона петли (div v-for each data text element)
  2. выбрать все page-break после рендеринга
  3. вычислений с использованием getBoundingClientRect()
    1. через цикл отбора
    2. получить расстояние между текущим перерывом и следующий
    3. , если он находится за пределами допустимого диапазона, удалите его из DOM.

Этот метод работает, но это очень некрасиво, это очень трудно вычислить хороший диапазон, и это супер дорого! При небольшом наборе данных, это нормально, но с целой книги, это слишком долго ...

И это первая попытка сделать это (с 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> 
Смежные вопросы