画像ポップアップのコンポーネントを作ってみる

フロント開発がもっと楽しくなる!Vue.js 学習メモ。サイトで使う画像ポップアップ用のコンポーネントを作ります。

最近 vue って打ちすぎて view が書けなくなってきました。前回親子関係のないコンポーネントのやり取りの勉強をしたのでそれを応用してこのサイトで使う画像ポップアップコンポーネントを作ってみました。

今回は単一コンポーネントファイルを使うため、まず前回の bus と同じく共有用に share.js というモジュールファイルを用意しました。

module.exports = {
popup: new Vue()
};

中身はこれだけです。

記事の中の <img-popup>画像</img-popup> という記述をリンク化するコンポーネントと、ポップアップウィンドウ用のコンポーネントの2つを作りました。 <popup-window> は適当に下の方に置いておきます。

var ImgPopup = require('./components/ImgPopup.vue')
var PopupWindow = require('./components/popup/window.vue')

new Vue({
    el: "#app",
    components: {
        ImgPopup,
        PopupWindow,
    }
});

img-popup.vue

[ERROR] 読み込みファイルがありません

link というスロットがあれば優先して使い、無ければデフォルトスロットをリンク要素にしています。クリックすると自分が持っている body  スロットまたはデフォルトスロットを Window コンポーネントに渡します。

Window.vue

<template>
<transition name="popup-overlay">
    <div class="popup-overlay" v-if="visible" @click.self="close">
        <div class="popup-inner">
            <!-- img があれば画像タグを表示、なければスロットを表示 -->
            <a v-bind:href="img" v-if="img"><img v-bind:src="img"></a>
            <slot v-else></slot>
            <div class="close" @click="close">×</div>
        </div>
    </div>
</transition>
</template>
<script>
var popup = require('../../lib/share.js').popup;
module.exports = {
    data: function() {
        return {
            img: null,
            visible: 0,
        }
    },
    methods: {
        close: function() {
            this.visible = 0;
        },
    },
    created: function() {
        var self = this;
        popup.$on('open', function(prop, elem) {
            self.$slots.default = prop.slot;
            self.img = prop.img;
            self.visible = 1;
        });
    }
}
</script>
<style>
.popup-overlay-enter-active,
.popup-overlay-leave-active {
    transition: opacity .4s
}

.popup-overlay-enter,
.popup-overlay-leave-to {
    opacity: 0
}

.popup-overlay {
    z-index: 110;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
}

.popup-inner {
    position: relative;
    display: inline-block;
    padding: 10px;
}

.popup-inner img {
    width: auto;
    height: auto;
}

.popup-inner .close {
    position: absolute;
    top: 0px;
    right: 0px;
    display: inline-block;
    cursor: pointer;
    color: #fff;
    font-size: 20px;
    line-height: 1;
    font-weight: bold;
    background: #000;
    border-radius: 100%;
    width: 20px;
    text-align: center;
}
</style>

Window コンポーネントは open イベントで img プロパティとスロットを受け取って表示させます。背景のオーバーレイだけクリックして閉じたかったので、 v-on:click.self モディファイアはすごく便利!

動作はこんな感じです。

<img-popup><img src="content/images/notebook/photoshop/201208/dotmosic_01.png" width="100" height="100"></img-popup>
<img-popup img="content/images/notebook/photoshop/201208/dotmosic_01.png">画像リンク</img-popup>

画像リンク

うーん、まあ動いたけど!

この方法だと渡しているスロットが Window.vue の Scoped CSS の範囲外になるのと、それ以前にスロットの渡し方とか何か気持ち悪いのでかなり改善するところがある気がすごくします。途中で描画関数とか調べてたのですがわからず。゚(゚´~`゚)゚。 一時的とか動的なコンポーネントの描画方法を勉強したいと思います。

もっとすてきなやり方が分かったら書き直しますね…。

Edited on 2017.02.23 Created on 2017.02.23 Vue.js JavaScript Webデザイン