Skip to content

Instantly share code, notes, and snippets.

@mikeapr4
Last active May 31, 2021 13:19
Show Gist options
  • Save mikeapr4/d05e0b64bac6b9a62549141edd389d8a to your computer and use it in GitHub Desktop.
Save mikeapr4/d05e0b64bac6b9a62549141edd389d8a to your computer and use it in GitHub Desktop.
wrap, extend or proxy a component
<template>
<HelloPopover />
</template>
<template>
<HelloPopover
class="myinstance"
style="font-style: normal; font-size: 1em"
role="button"
nonsense="true"
/>
</template>
<template>
<HelloPopover>
<h1>Click here</h1>
<template #popover>Hello World!</template>
</HelloPopover>
</template>
<template>
<div id="app">
<button @click="open = !open">Toggle</button>
<HelloPopover
:open.sync="open"
:style="{ background: highlight ? 'cyan' : 'none' }"
@mouseover.native="highlight = true"
@mouseout.native="highlight = false"
>
<h1>Click here</h1>
<template #popover>Hello World!</template>
</HelloPopover>
</div>
</template>
<template>
<div id="app">
<button @click="open = !open">Toggle</button>
<HelloPopover :open.sync="open">
<template v-slot="{ attrs, listeners }">
<v-popover
v-bind="attrs"
v-on="listeners"
:style="{ background: highlight ? 'cyan' : 'none' }"
@mouseover.native="highlight = true"
@mouseout.native="highlight = false"
>
<h1>Click here</h1>
<template #popover>Hello World!</template>
</v-popover>
</template>
</HelloPopover>
</div>
</template>
<template>
<div id="app">
<button @click="open = !open">Toggle</button>
<HelloPopover v-model="open">
<template v-slot="hp">
<v-popover
:open.sync="hp.isOpen"
:style="{ background: highlight ? 'cyan' : 'none' }"
@mouseover.native="highlight = true"
@mouseout.native="highlight = false"
>
<h1>Click here</h1>
<template #popover>Hello World!</template>
</v-popover>
</template>
</HelloPopover>
</div>
</template>
<template>
<v-popover>
<h1>Click here</h1>
<template #popover>Hello World!</template>
</v-popover>
</template>
<template>
<v-popover
class="helloworld"
style="font-style: italic; line-height: 1em"
role="dialog"
>
...
<template>
<v-popover
v-bind="$attrs"
v-on="$listeners"
>
<template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope">
<slot :name="slot" v-bind="scope"/>
</template>
</v-popover>
</template>
<template>
<!-- open prop and event separately bound -->
<v-popover
v-bind="$attrs"
:open="isOpen"
v-on="proxyListeners"
@update:open="isOpen = $event"
>
<template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope"
><slot :name="slot" v-bind="scope"
/></template>
</v-popover>
</template>
<script>
import { VPopover } from "v-tooltip";
export default {
components: { VPopover },
// Expose an explicit prop for open
props: {
open: { type: Boolean, default: false },
},
data() {
return {
// a locally modifiable value for open
isOpen: this.open,
waitID: 0,
};
},
computed: {
// Provide the listeners to bind, with any open update listener removed
proxyListeners() {
const { "update:open": updateOpen, ...others } = this.$listeners;
return others;
},
},
watch: {
// Incoming prop updates should be received
open(val) {
this.isOpen = val;
},
// Any time the popover opens/closes, this handler runs
// If opened, a 5sec timer is started which will auto-close
// the popover
isOpen: {
handler(val) {
if (this.waitID) {
clearTimeout(this.waitID);
this.waitID = 0;
}
if (val) {
this.waitID = setTimeout(() => {
this.isOpen = false;
}, 5000);
}
this.$emit("update:open", val);
},
immediate: true,
},
},
};
</script>
<template functional>
<v-popover
v-bind="data.attrs"
v-on="listeners"
>
<template v-for="(_, slot) of scopedSlots" v-slot:[slot]="scope"
><slot :name="slot" v-bind="scope"
/></template>
</v-popover>
</template>
import { VPopover } from "v-tooltip";
export default {
functional: true,
render(h, { data, children }) {
return h(
VPopover,
{
...data,
props: {
...data.props,
popoverClass: "helloworld",
},
},
children
);
},
};
export default {
render(h) {
// Render default slot, if there are multiple nodes, Vue
// will give a sensible warning, so no need for a safety.
return this.$scopedSlots.default({
// For abstraction the attrs/listeners are passed as objects,
attrs: { open: this.isOpen },
listeners: {
"update:open": (val) => (this.isOpen = val),
},
});
},
// Expose an explicit prop for open
props: {
open: { type: Boolean, default: false },
},
data() {
return {
// a locally modifiable value for open
isOpen: this.open,
waitID: 0,
};
},
watch: {
// Incoming prop updates should be received
open(val) {
this.isOpen = val;
},
// Same as Tapped Props example (HelloPopover-3.vue)
isOpen: { ... },
},
};
export default {
render(h) {
return this.$scopedSlots.default(this);
},
props: {
value: { type: Boolean, default: false },
},
data() {
return {
// a locally modifiable value for open
isOpen: this.open,
waitID: 0,
};
},
watch: {
// Incoming prop updates should be received
value(val) {
this.isOpen = val;
},
// Any time the popover opens/closes, this handler runs
// If opened, a 5sec timer is started which will auto-close
// the popover
isOpen: {
handler(val) {
if (this.waitID) {
clearTimeout(this.waitID);
this.waitID = 0;
}
if (val) {
this.waitID = setTimeout(() => {
this.isOpen = false;
}, 5000);
}
this.$emit("input", val);
},
immediate: true,
},
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment