背景
長い文字列は末尾を三点リーダに変換したい
例えばECサイトとかで商品が一覧で並んでいるときに、
長ーい商品名のアイテムだけ高さがずれたらダサい。
僕.「cssだけでできる?」
G .「IEは対応してないけど良い?」
僕.「(IEからも割とアクセスされえるので)だめ」
※Gはgoogle検索
僕.「ではscriptで対応するか・・・。」
G .「これなんか参考にならんか? あとこれとか」
僕.「JQuery使ってるやつばっかやん。」
僕.「うちJQuery使ってないねん。」
僕.「あー。あとriot使ってるんでそっちで対応したい」
G .「該当ありません」
僕.「ぐぬぬ」
条件
- 表示する文字列が長い時に、描画領域で特定の高さになるように末尾を省略して三点リーダにして表示する
- riotjs使っているのでパーツをriotのtagで用意したい
- IEでも動く
- jQueryは使わない
今回は上記縛りから色々苦労した。
実装方法
<ellipsis>
<p class="{opts.class}">
{text}
</p>
<script>
let tag = this
tag.text = this.opts.text
// DOMが生成されてから実行するため
this.on('mount', function(){
// riotはthis.rootでエレメントにアクセスできる
let element = this.root.querySelector('p');
// 計算用エレメントの用意
let clone = element.cloneNode(true)
clone.style.position = 'absolute'
clone.style.overflow = 'visible'
clone.style.height = 'auto'
clone.style.width = document.defaultView.getComputedStyle(element, null).width
this.root.appendChild(clone)
let html = element.innerHTML
let height = parseFloat(document.defaultView.getComputedStyle(element, null).height)
let shorten_cnt = 0
// cloneの高さが用意された領域に収まるまで文字をカットしていく
while((html.length > 0) && (parseFloat(document.defaultView.getComputedStyle(clone, null).height) > height)) {
html = html.substr(0, html.length - 1);
clone.innerHTML = html + '...';
// 文字列が長すぎた場合ループ回数が増えすぎるので保険として
if (shorten_cnt > 1000) {
break;
}
shorten_cnt++
}
// cloneは計算にしか使わないので削除
this.root.removeChild(clone)
// 最初から高さ内に収まっている場合は何もしない
if (shorten_cnt > 0) {
tag.text = html + '...'
tag.update()
}
})
</script>
</ellipsis>
呼ぶところ
<ellipsis text="眠い時には何をやっても眠いので、いっそお昼寝すればいいと思うのですが、会社で大ぴらに眠ることも流石に気がひけるのでタイピングしながら眠る術を身につけた(嘘" class="height_40"></ellipsis>
こうしておけば長さに合わせて三点リーダーが挿入される
<p class="height_40">眠い時には何をやっても眠いので、いっそお昼寝すればいい... </p>
詰まりポイント説明
this.on('mount')
riotマウント後でないとDOMが生成されてないので、mount時に呼ばれる関数内に処理を書く。
cloneNode
単に
let clone = element
ってしてしまうと参照渡しになってしまうのでcloneNode(true)でディープコピー
display:noneは?
参考サイトにはcloneしたものをdisplay:noneすべし、ってなっていますが、
riotの場合、heightがautoのままになって計算できなくなってしまうみたいなので外した。
どうせ処理後に消されるので(もしかしたらちらつくかも)
parseFloat
これ使わないと
document.defaultView.getComputedStyle(clone, null).height
が「20px」とかの文字列となり、比較できないのでFloat型に変換。
数値になるように「px」とかいった無用な文字列も削除してくれるようだ。
参考
以下、参考にさせていただきました。
ありがとうございます。