/ Gists / My Modal with v-model
On gists

My Modal with v-model

Vue.js

app.js Raw #

<script setup>
import { ref } from 'vue'
import Modal from './Modal.vue'

const openByRef = ref(false)

setTimeout(() => {
  openByRef.value = true
}, 2000)
</script>

<template>
  <Modal v-model="openByRef">

    <template #buttons="slotProps">
      inner state: {{ slotProps.opened }} <br />
      outer state: {{ openByRef }} <br /><br />
      <button @click="slotProps.open()">open</button> | 
      <button @click="slotProps.close()">close</button>
  
      <br /><br />
    </template>

    <template #default="slotProps">
      OBSAH MODALU
    </template>

  </Modal>
</template>

Modal.vue Raw #

<script setup>
import { ref, defineProps, defineEmits, computed, watch } from 'vue';

const emit = defineEmits(['update:modelValue']);

const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false
  }
});

// Vnitřní stav pro otevření modalu
const internalOpened = ref(props.modelValue);

// Sledování změn z vnějšího modelu (pokud je používán)
watch(() => props.modelValue, (newVal) => {
  internalOpened.value = newVal;
});

// Computed property pro sledování a nastavování stavu
const opened = computed({
  get() {
    return internalOpened.value;
  },
  set(value) {
    internalOpened.value = value // internal state
    emit('update:modelValue', value); // external for outside v-model
  }
});

const open = () => {
  opened.value = true;
};

const close = () => {
  opened.value = false;
};
</script>

<template>
  <slot name="buttons" v-bind="{ open, close, opened }" />
  <slot name="debug">open by ref {{ internalOpened }} / {{ opened }}</slot>
  
  <template v-if="opened">
    <div class="Modal">
      <slot />
      <hr />
      <button @click="close">close [x]</button>
    </div>
  </template>
</template>

<style>
.Modal {
  width: 200px;
  height: 200px;
  background: rgb(0 0 0 / 0.3);
  padding: 1rem;
}
</style>