iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

我的Vue學習筆記系列 第 28

Day28-實作(燈箱)

做完了側選單就要進入到第二區塊 — 燈箱

首先,在src/components下新增lightbox.vue(內容取自此連結)

<template>
  <transition name="modal">
    <div class="modal-mask" v-show="showModal">
		<!-- 為了可以關閉燈箱,加上@click.self="close" -->
      <div class="modal-wrapper" @click.self="close">
        <div class="modal-container">
          <div class="modal-body">
            <!-- 內容放這裡 -->
            <div>Hello</div>
          </div>
        </div>

      </div>
    </div>
  </transition>
</template>

<script>
	export default {
	  name: 'Lightbox',
	  computed: {
	    showModal: {
	      get() {
	        return this.$store.state.showModal;
	      },
	      set(value) {
	        this.$store.commit('setshowModal', value);
	      },
	    },
	  },
	  methods: {
	    close() {
	      this.showModal = false;
	    },
	  },
	};
</script>

<style scoped lang="scss">
.modal-mask {
  position: fixed;
  z-index: 100;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, .65);
  display: table;
  transition: opacity .3s ease;
}
.modal-wrapper {
  display: table-cell;
  vertical-align: middle;
}
.modal-container {
  width: 520px;
  margin: 0px auto;
  padding: 10px 30px;
  background-color: #fff;
  border-radius: 5px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
  transition: all .3s ease;
  font-family: Helvetica, Arial, sans-serif;
}
.modal-body {
  color: #42b983;
  margin: 20px 0;
}
</style>

<style>
.modal-enter {
  opacity: 0;
}
.modal-leave-active {
  opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
  transform: scale(1.1);
}
</style>

<style lang="scss" scoped>
.store-name {
  font-size: 1.6rem;
  font-weight: bold;
  line-height: 1.5;
}
.title{
  font-weight: 500;
  margin-bottom: .5rem;
  line-height: 1.7;
}
table {
  border-spacing: 0;
  border-radius: 3px;
  width: 100%;
  margin-bottom: 1rem;
}
th{
  background-color: #42b983;
  color: #fff;
}
td, th{
  padding: .3em;
  text-align: center;
  line-height: 1.5rem;
}
</style>

並在store/index.js中新增showModal

state: {
  currCity: '臺北市',
  currDistrict: '北投區',
  location: [],
  stores: [],
  keywords: '',
  showModal: false
},

及相對應的mutations

setshowModal(state, payload) {
  state.showModal = payload
}

接著修改App.vue,加入lightBox.vue

import { mapActions } from "vuex";
import asideMenu from "./components/asideMenu.vue";
import lightBox from "./components/lightBox.vue";

export default {
  name: "App",
  components: {
    asideMenu,
    lightBox,
  },
  methods: {
    ...mapActions(["fetchLocations", "fetchPharmacies"]),
  },
  mounted() {
    this.fetchLocations();
    this.fetchPharmacies();
  },
};

側選單處可以控制modal的開關,所以要回到asideMenu.vue加入對應的showModal控制屬性

computed: {
    currCity: {...},
    currDistrict: {...},
    keywords: {...},
    ...mapGetters(["cityList", "districtList", "filteredStores"]),
    showModal: {
      get() {
        return this.$store.state.showModal;
      },
      set(value) {
        this.$store.commit("setshowModal", value);
      },
    },
  },

以及相關的methods

openInfoBox() {
  this.showModal = true;
},

還有要去模板那增加click事件

<button class="btn-store-detail" @click="openInfoBox()">
  <i class="fas fa-info-circle"></i>
  看詳細資訊
</button>

到這個步驟已經可以看到一個簡易的畫面,如下圖

Untitled

再來就是要修改一下燈箱裡面的內容

<div class="modal-body">
  <h1 class="store-name">藥局名稱</h1>
  <hr>
  <h2 class="title">營業時間</h2>
  <table>
    <thead>
      <tr>
        <th></th>
        <th>ㄧ</th>
        <th>二</th>
        <th>三</th>
        <th>四</th>
        <th>五</th>
        <th>六</th>
        <th>日</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th>早上</th>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
      </tr>
      <tr>
        <th>中午</th>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
      </tr>
      <tr>
        <th>晚上</th>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
      </tr>
    </tbody>
  </table>

  <h2 class="title">地址 XXXXXXX</h2>
  <h2 class="title">電話 XXXXXXX</h2>
  <h2 class="title">備註 XXXXXXX</h2>
</div>

修改後可以看到以下畫面

Untitled

有了畫面但沒有資料,所以下一步就是要想辦法讓資料生出來。從列表中要取得藥局的資訊,我們可以利用藥局的id來渲染資料,先在state中新增一個infoBoxSid

state: {
  currCity: '臺北市',
  currDistrict: '北投區',
  location: [],
  stores: [],
  keywords: '',
  showModal: false,
	infoBoxSid: null
},

以及mutations

setInfoBoxSid(state, payload) {
  state.infoBoxSid = payload
}

接下來就是在asideMenu.vue和lightBox.vue加上computed屬性

infoBoxSid: {
  get() {
    return this.$store.state.infoBoxSid;
  },
  set(value) {
    this.$store.commit("setinfoBoxSid", value);
  },
},

改寫asideMenu.vue的openInfoBox,讓他可以帶入藥局的id

openInfoBox(sid) {
  this.showModal = true;
  this.infoBoxSid = sid;
},

當然模板也要改一下

<button class="btn-store-detail" @click="openInfoBox(s.id)">
  <i class="fas fa-info-circle"></i>
  看詳細資訊
</button>

同時,在lightBox.vue的computed新增以下內容,就可以找到對應的藥局資訊

currStore() {
  return this.$store.state.stores.filter(
    (d) => d.id === this.infoBoxSid
  )[0];
},

Untitled

營業的時間內容放在service_periods這個欄位,我們要把NNNNNNYNNNNNNYNNNNNNY拆解成我們需要的內容,所以在lightBox.vue中computed加上servicePeriod

servicePeriods() {
  let servicePeriods = this?.currStore?.["service_periods"] || "";
  servicePeriods = servicePeriods.replace(/N/g, "O").replace(/Y/g, "X");

  return servicePeriods
    ? [
        servicePeriods.slice(0, 7).split(""),
        servicePeriods.slice(7, 14).split(""),
        servicePeriods.slice(14, 21).split(""),
      ]
    : servicePeriods;
},

可以看到內容被我們變成這樣了

Untitled

再來就是修改燈箱模版

<div class="modal-body">
    <h1 class="store-name">{{ currStore.name }}</h1>
    <hr />
    <h2 class="title">營業時間</h2>
    <table>
      <thead>
        <tr>
          <th></th>
          <th>ㄧ</th>
          <th>二</th>
          <th>三</th>
          <th>四</th>
          <th>五</th>
          <th>六</th>
          <th>日</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>早上</th>
          <td v-for="(s, idx) in servicePeriods[0]" :key="idx">
            {{ s }}
          </td>
        </tr>
        <tr>
          <th>中午</th>
          <td v-for="(s, idx) in servicePeriods[1]" :key="idx">
            {{ s }}
          </td>
        </tr>
        <tr>
          <th>晚上</th>
          <td v-for="(s, idx) in servicePeriods[2]" :key="idx">
            {{ s }}
          </td>
        </tr>
      </tbody>
    </table>

    <h2 class="title">地址 {{ currStore.address }}</h2>
    <h2 class="title">電話 {{ currStore.phone }}</h2>
    <h2 class="title" v-if="currStore.custom_note">
      備註 {{ currStore.custom_note }}
    </h2>
  </div>

若一開始沒有currStore的情況下找不到currStore.name會跳錯,此時可以在modal加上v-if解決錯誤。

<div class="modal-body" v-if="currStore"></div>

上一篇
Day27-實作(列表區) (part2)
下一篇
Day29-實作(地圖) (part1)
系列文
我的Vue學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
juck30808
iT邦研究生 1 級 ‧ 2021-10-14 12:13:13

恭喜即將邁入完賽~/images/emoticon/emoticon08.gif

hsiu753 iT邦新手 4 級 ‧ 2021-10-14 19:22:48 檢舉

也恭喜你!!! 我們都剩下一天了

我要留言

立即登入留言