2
votes

I wrote the following in Vue 3 Composition API.

If you look on the "onMounted" I'm attaching an event listener to the window to keep the status box to the bottom of the screen. I'm using absolute position and bottom 0.

I'm wondering if I can make this more "Vue" by replacing the getElementById? I tried refs but it's not working.

Any suggestions or should I leave well enough alone?

Thanks

<template>
  <div>
    <transition name="toast">
      <div id="slide" class="slide-modal" v-if="statuses.length">
        <div class="clear-notifications" @click='clearAllNotifications()'>Clear all notifications</div>
        <div v-for="status in statuses" :key="status.id" class="status-div">
          <div>{{ status.text }}</div>
          <div @click="closeStatus(status)"><span class="-x10-cross"></span></div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref, computed, watch, onMounted } from "vue";
  import { useStore } from "../model/DataStore";
  export default defineComponent({ 
    setup() {
    const store = useStore();

    const statuses = ref([]);

    const statusMessage = computed(() => store.state.statusMessage);
    function  addStatus(newMessage) {

          statuses.value.push({
            id: statuses.value.length + 1,
            text: newMessage
          })
        }

      watch(statusMessage, (newValue: string, oldValue: string) => {
        addStatus(statusMessage.value);
      })

      onMounted(() => {
          window.addEventListener("scroll", function (e) {
                let vertical_position = 0;
                vertical_position = pageYOffset;

                if(document.getElementById("slide")){
                  document.getElementById('slide').style.bottom = -(vertical_position) + 'px';
                }
          });
      })

    return {
      store,
      statuses,
      addStatus
    };
  },
  methods: {
        clearAllNotifications() {
          this.statuses = []
        },

        closeStatus(elm: any) {
          const index = this.statuses.map((status) => status.id).indexOf(elm.id);
          this.statuses.splice(index, 1);
        }
      }
  })
</script>

and here's the slide modal style:

    .slide-modal {
        max-height: 200px;
        width: 500px;
        background-color: #f2f2f2;
        color: #505050;
        padding: 8px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        overflow-x: hidden;
        position: absolute;
        bottom: 0;
    }
1
What is the code when you replace to ref?Epic Chen
if(document.getElementById("slide")){ document.getElementById('slide').style.bottom = -(vertical_position) + 'px'; }user581733
I want to not use the document.getElementById.user581733

1 Answers

3
votes

The docs give a pretty simple example

<template>
  <div ref="root">This is a root element</div>
</template>

<script>
  import { ref, onMounted } from 'vue'

  export default {
    setup() {
      const root = ref(null)

      onMounted(() => {
        // the DOM element will be assigned to the ref after initial render
        console.log(root.value) // <div>This is a root element</div>
      })

      return {
        root
      }
    }
  }
</script>
  • use ref() when creating
  • pass to template in return function
  • use ref="..." in template
  • and in onMounted, access via ref.value

so for your code it would be...

<template>
  <div>
    <transition name="toast">
      <div ref="slideRef" class="slide-modal" v-if="statuses.length">
        <div class="clear-notifications" @click='clearAllNotifications()'>Clear all notifications</div>
        <div v-for="status in statuses" :key="status.id" class="status-div">
          <div>{{ status.text }}</div>
          <div @click="closeStatus(status)"><span class="-x10-cross"></span></div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref, computed, watch, onMounted } from "vue";
  import { useStore } from "../model/DataStore";
  export default defineComponent({ 
    setup() {
    const store = useStore();

    const statuses = ref([]);
    const slideRef = ref();

    const statusMessage = computed(() => store.state.statusMessage);
    function  addStatus(newMessage) {
          statuses.value.push({
            id: statuses.value.length + 1,
            text: newMessage
          })
        }

      watch(statusMessage, (newValue: string, oldValue: string) => {
        addStatus(statusMessage.value);
      })

      onMounted(() => {
          window.addEventListener("scroll", function (e) {
                let vertical_position = 0;
                vertical_position = pageYOffset;

                if(slideRef.value){
                  slideRef.value.style.bottom = -(vertical_position) + 'px';
                }
          });
      })

    return {
      store,
      statuses,
      addStatus,
      slideRef 
    };
  },
  })
</script>