2016-12-06 18 views
11

Buduję narzędzie do generowania pliku PDF z danych i muszę budować w dwóch formatach: 105mm * 148mm i 105mm * 210mm. Dostałem więc cały dokument, a teraz nadszedł czas, aby wstawić podziały strony. Robię to w prostej klasie:Jakie jest najlepsze podejście do obliczania odległości między elementami DOM w Vuejs?

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

Teraz muszę wstawić tę klasę do mojej pętli v-for. Podstawowym założeniem jest obliczenie przedziału, tak jak każdy indeks jest wielokrotnością 6, wstawiam jeden. Ale to nie jest najlepszy sposób, aby to zrobić, chcę wstawić przerwę, gdy zawartość jest powyżej 90 mm.

W tym celu chciałem obliczyć odległość między 2 przerwami i wstawić nową, jeśli odległość jest bliska 90 mm. Ale nie mogę znaleźć sposobu na dostęp do dynamicznych elementów DOM ...

Pytanie jest więc proste: jak obliczyć odległość? A jeśli istnieje lepszy sposób osiągnięcia mojego celu, co mogę poprawić?

+0

to możliwe, aby dodać trochę kodu. –

+0

@ hardik-satasiya done –

Odpowiedz

3

Wierzę, że dodajesz div/component w każdym v-for i możesz dodać unikalny identyfikator do każdego div. Teraz poniżej metody mogą dać ci wysokość jednego div w px, a będziesz miał sposób na konwersję px na mm.

Jeśli używasz jquery można zrobić

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

Jeśli nie, można to zrobić następujące:

inner height:

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

outer height:

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

jeśli podany kod:

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

Trzeba dodać następujący sposób:

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 
     } 
} 

Trzeba dodać następujące hash oraz w atrybucie danych elemencie vue, który będzie na bieżąco śledzić co co indeksy został dodany podział strony:

pageBreakAdded: {} 
+0

Dobry pomysł z warunkiem 'v-if', być może będzie on szybszy. –

+0

@GeorgeAbitbol Czy uważasz, że to podejście jest przydatne, czy widzisz tutaj jakieś obawy? – Saurabh

+0

@Saurabh, Wydaje się, że opanowałeś vue.js. Potrzebuję twojej pomocy. Zajrzyj tutaj: http://stackoverflow.com/questions/41843823/how-to-display-button-link-with-vue-js –

2

Tak, próbowałem tej metody:

  1. wstawić page-break wewnątrz mojego szablonu pętli (div v-for each data text element)
  2. zaznaczyć cały page-break po renderingu
  3. obliczeniowych przy użyciu getBoundingClientRect()
    1. pętlę poprzez dobór
    2. uzyskać odległość między aktualnym przerwy i następujący kod:
    3. jeśli jest poza akceptowalnym zakresem, usuń go z DOM.

Ta metoda działa, ale jest to bardzo brzydki, to jest bardzo trudne do obliczenia dobry wybór, a to bardzo drogie! Z małym zbiorze jest ok, ale z całą książkę, to zbyt długo ...

I jest to pierwsza próba to zrobić (z Vue szablonów)

<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>