Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] how to make a custom click outside directive from scratch #666

Open
nesteiner opened this issue Mar 14, 2023 · 0 comments
Open

Comments

@nesteiner
Copy link

nesteiner commented Mar 14, 2023

This problem has troubled me for a long time, seems that you can help me.
I made a click outside directive too, this is my code

import { DirectiveBinding, ObjectDirective } from "vue";

let func: ((event: MouseEvent) => void) | null = null
const ClickOutside: ObjectDirective = {
  mounted: (el: HTMLElement, binding: DirectiveBinding) => {
    func = (event: MouseEvent) => {
      let result = (!(el === event.target || el.contains(event.target as Node)))
      console.log(result)
      if (result) {
        binding.value()
      }
    }

    document.addEventListener("click", func)
  },
  
  unmounted: (el: HTMLElement) => {
    if (func != null) {
      document.removeEventListener("click", func)
    }
  }
}

export default ClickOutside

when using it like below, everything is ok

<div class="click-outside">
     <div class="box" ref="box" v-click-outside="onblur"/>
</div>
const onblur = () => {
  console.log("you have click outside the box")
}
2023-03-14.20-37-52.mp4

but when using it at the dialog, it is not ok
this is the dialog code

<template>
  <Center class="dialog" v-if="show">
    <Column class="container" v-click-outside="onblur" :style="containerStyle">
      <Row class="close" main-axis-aligment="space-between" cross-axis-aligment="center" cross-axis-size="min">
        <h3> {{ title }} </h3>
        <CloseIcon @click="onblur"/>
      </Row>

      <Column class="content" main-axis-size="min" cross-axis-size="max" cross-axis-aligment="center" main-axis-aligment="space-between" :style="contentStyle">
        <div>
          <slot/>
        </div>

        <Row class="footer" main-axis-aligment="end" cross-axis-size="min">
          <slot name="footer"/>
        </Row>
      </Column>
    </Column>
  </Center>
</template>

<script lang="ts" setup>
import {Row, Column, Center} from "scratch-components"
import CloseIcon from "./CloseIcon.vue"
import {ClickOutside as vClickOutside} from "@/directives"
import { computed, onMounted } from "vue";

interface DialogProps {
  show: boolean,
  scrollable?: boolean,
  title?: string
}

const props = withDefaults(
  defineProps<DialogProps>(), 
  {
    scrollable: false,
    title: ""
  }
)

const emits = defineEmits(["update:show"])

const containerStyle = computed(() => {
  if (props.scrollable) {
    return {
      maxWidth: "60%",
      maxHeight: "70%"
    }
  } else {
    return {

    }
  }
})
const contentStyle = computed(() => {
  if (props.scrollable) {
    return {
      overflow: "scroll",
    }
  } else {
    return {
      overflow: "hidden"
    }
  }
})

const onblur = () => {
  emits("update:show", false)
}

onMounted(() => {
  console.log("mounted")
})
</script>

when using it

<div class="dialog">
      <button @click="showDialog2"> Click me to show Dialog </button>
</div>

<Dialog v-model:show="openDialog2" title="hello world">
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>
      <h1> Hello World </h1>

      <template #footer>
        <button>Hello</button>
        <button>World</button>
      </template>
    </Dialog>
2023-03-14.17-19-27.mp4

as you can see, I can't open the dialog
I found the reason is that <Dialog> has already mounted when pass the show with false, I don't know how do you fix this in your code
or can you help me improve my code ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant