🐛[修复bug]解决tooltip内容动态更新和深色主题边框白边的问题,新增禁用属性(disabled)
This commit is contained in:
parent
6dd0bd791f
commit
25ee7195f0
@ -52,11 +52,60 @@
|
|||||||
::: demo
|
::: demo
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<lay-tooltip content="假装这里有文字提示" :is-dark="false">
|
<lay-tooltip content="不明白是是非非,只知我不会不在。" :is-dark="false">
|
||||||
<lay-button>tooltip</lay-button>
|
<lay-button >tooltip</lay-button>
|
||||||
</lay-tooltip>
|
</lay-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: title 是否禁用/动态属性
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: demo
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<lay-tooltip :content="content" :is-dark="isDark" :disabled="!disabled">
|
||||||
|
<lay-button>tooltip</lay-button>
|
||||||
|
</lay-tooltip>
|
||||||
|
<lay-switch v-model="disabled" active-text="启用tooltip" inactive-text="禁用tooltip" style="margin-left: 5px;"></lay-switch>
|
||||||
|
<lay-switch v-model="isDark" active-text="深色" inactive-text="浅色" style="margin-left: 5px;"></lay-switch>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
const contentArr = [
|
||||||
|
"不明白是是非非,只知我不会不在。",
|
||||||
|
"千山万水,去程是你,归程也是你。",
|
||||||
|
"一约既定,万山无阻。",
|
||||||
|
"时光都淡了,我还伴着你。",
|
||||||
|
"只问深情,不问西东。",
|
||||||
|
"感谢曾经在我身边的,一直在我身边。",
|
||||||
|
"经年再相逢,魂梦与子同。"
|
||||||
|
];
|
||||||
|
const rendonCotent = function(){
|
||||||
|
return contentArr[Math.floor(Math.random() * contentArr.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
const content = ref(rendonCotent())
|
||||||
|
const isDark = ref(false)
|
||||||
|
const disabled = ref(true)
|
||||||
|
|
||||||
|
setInterval(()=> content.value = rendonCotent(), 1000)
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
isDark,
|
||||||
|
disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
:::
|
:::
|
||||||
@ -71,5 +120,6 @@
|
|||||||
| content | 显示内容 | -- |
|
| content | 显示内容 | -- |
|
||||||
| position | 显示位置 | `top`(默认值)、`bottom`、`left`、`right` |
|
| position | 显示位置 | `top`(默认值)、`bottom`、`left`、`right` |
|
||||||
| isDark | 是否为黑色主题 | `true`(默认值)、`false`(浅色) |
|
| isDark | 是否为黑色主题 | `true`(默认值)、`false`(浅色) |
|
||||||
|
| disabled | 是否禁用 | `false`(默认值)、`true`(禁用) ||
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
@ -31,7 +31,7 @@ const postionFns: any = {
|
|||||||
left = right;
|
left = right;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
top: `${top - Math.abs(popper.offsetHeight - el.offsetHeight) / 2}px`,
|
top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`,
|
||||||
left: `${left}px`
|
left: `${left}px`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -42,7 +42,7 @@ const postionFns: any = {
|
|||||||
right = left - popper.offsetWidth - 6;
|
right = left - popper.offsetWidth - 6;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
top: `${top - Math.abs(popper.offsetHeight - el.offsetHeight) / 2}px`,
|
top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`,
|
||||||
left: `${right}px`
|
left: `${right}px`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,16 @@
|
|||||||
@border-clor: #cecece;
|
@border-clor: #cecece;
|
||||||
|
|
||||||
// 单一设置主题
|
// 单一设置主题
|
||||||
.single-theme(@position, @contrary_position, @margin_postion, @color) {
|
.single-theme(@position, @contrary_position, @margin_postion, @color, @m-border-color) {
|
||||||
@attr : ~'[position=@{position}]';
|
@attr : ~'[position=@{position}]';
|
||||||
&.layui-popper@{attr}{
|
&{
|
||||||
|
border: 1px solid @m-border-color;
|
||||||
|
&.layui-popper@{attr}{
|
||||||
margin-@{contrary_position}: 6px;
|
margin-@{contrary_position}: 6px;
|
||||||
.layui-popper-arrow {
|
.layui-popper-arrow {
|
||||||
@{contrary_position}: -6px;
|
@{contrary_position}: -6px;
|
||||||
border-@{contrary_position}-width: 0;
|
border-@{contrary_position}-width: 0;
|
||||||
border-@{position}-color: @border-clor;
|
border-@{position}-color: @m-border-color;
|
||||||
&::after{
|
&::after{
|
||||||
@{contrary_position}: 1px;
|
@{contrary_position}: 1px;
|
||||||
border-@{contrary_position}-width: 0;
|
border-@{contrary_position}-width: 0;
|
||||||
@ -26,15 +28,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 统一设置四个方向的主题
|
// 统一设置四个方向的主题
|
||||||
.theme(@background-color, @color) {
|
.theme(@background-color, @color, @border-color) {
|
||||||
background-color: @background-color;
|
background-color: @background-color;
|
||||||
color: @color;
|
color: @color;
|
||||||
.single-theme(top, bottom, left, @background-color);
|
.single-theme(top, bottom, left, @background-color, @border-color);
|
||||||
.single-theme(bottom, top, left, @background-color);
|
.single-theme(bottom, top, left, @background-color, @border-color);
|
||||||
.single-theme(right, left, top, @background-color);
|
.single-theme(right, left, top, @background-color, @border-color);
|
||||||
.single-theme(left, right, top, @background-color);
|
.single-theme(left, right, top, @background-color, @border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 箭头默认居中
|
// 箭头默认居中
|
||||||
@ -65,9 +68,8 @@
|
|||||||
min-height: 12px;
|
min-height: 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid @border-clor;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.15);
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.15);
|
||||||
.theme(@ligh-background, @ligh-color);
|
.theme(@ligh-background, @ligh-color, @border-clor);
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
|
|
||||||
@ -93,8 +95,7 @@
|
|||||||
|
|
||||||
/* 深色主题 */
|
/* 深色主题 */
|
||||||
&.layui-dark {
|
&.layui-dark {
|
||||||
.theme(@dark-background, @dark-color);
|
.theme(@dark-background, @dark-color, @dark-background);
|
||||||
border: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition v-if="visible">
|
<transition v-show="visible">
|
||||||
<div :class="['layui-popper', {'layui-dark' : isDark}]" :style="style" :position="innnerPosition">
|
<div ref="popper" :class="['layui-popper', {'layui-dark' : innnerIsDark}]" :style="style" :position="innnerPosition">
|
||||||
<slot>{{content}}</slot>
|
<slot>{{content.value}}</slot>
|
||||||
<div class="layui-popper-arrow"></div>
|
<div class="layui-popper-arrow"></div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
@ -16,22 +16,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import postionFns from "./calcPosition";
|
import postionFns from "./calcPosition";
|
||||||
import { getCurrentInstance, CSSProperties, ref, watch, onUpdated, defineEmits, onMounted, des} from "vue";
|
import { CSSProperties, ref, watch, onUpdated, defineEmits, onMounted, Ref} from "vue";
|
||||||
import {on} from "../../tools/domUtil";
|
import {on} from "../../tools/domUtil";
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
el : any,
|
el : any,
|
||||||
content ?: string,
|
content ?: Ref<string>,
|
||||||
position ?: string,
|
position ?: Ref<string>,
|
||||||
trigger ?: string,
|
trigger ?: string,
|
||||||
enterable ?: boolean,
|
enterable ?: boolean,
|
||||||
isDark ?: boolean,
|
isDark ?: Ref<boolean>,
|
||||||
|
disabled ?: Ref<boolean>,
|
||||||
modelValue ?: boolean
|
modelValue ?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
position : 'top',
|
|
||||||
enterable : true,
|
enterable : true,
|
||||||
isDark : false,
|
|
||||||
trigger : 'hover',
|
trigger : 'hover',
|
||||||
modelValue : true
|
modelValue : true
|
||||||
}
|
}
|
||||||
@ -48,43 +47,50 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = ref<CSSProperties>({top: (-window.innerHeight) + 'px',left:0});
|
const style = ref<CSSProperties>({top: (-window.innerHeight) + 'px',left:0});
|
||||||
const visible = ref(props.modelValue);
|
|
||||||
const checkTarget = ref(false);
|
const checkTarget = ref(false);
|
||||||
const popper = ref();
|
const popper = ref<HTMLDivElement>({} as HTMLDivElement);
|
||||||
const innnerPosition = ref(props.position);
|
const tempPosition = props.position??ref('top');
|
||||||
|
const innnerPosition = ref(tempPosition.value);
|
||||||
|
const innnerIsDark = ref(props.isDark??true);
|
||||||
|
const innnerDisabled = ref(props.disabled??false);
|
||||||
|
const visible = ref(props.modelValue && !innnerDisabled.value);
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
watch(visible, (val)=>{
|
watch(visible, (val)=>{
|
||||||
emit('update:modelValue', val);
|
emit('update:modelValue', val);
|
||||||
|
val && (popper.value.offsetWidth === 0 ? setTimeout(showPosistion, 0) : showPosistion());
|
||||||
|
})
|
||||||
|
watch(innnerDisabled, (val)=>{
|
||||||
|
visible.value = false;
|
||||||
|
})
|
||||||
|
watch(()=>props.content?.value, (val)=>{
|
||||||
|
visible.value && setTimeout(showPosistion, 5);
|
||||||
})
|
})
|
||||||
|
|
||||||
const doShow = function(){
|
const doShow = function(){
|
||||||
visible.value = true;
|
if (!innnerDisabled.value) {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const doHidden = function(e : MouseEvent){
|
const doHidden = function(e : MouseEvent){
|
||||||
if ((checkTarget.value && props.el.contains(e.target)) || (props.enterable && popper.value.contains(e.target))) return;
|
if ((checkTarget.value && props.el.contains(e.target)) || (props.enterable && popper.value.contains(e.target as Node))) return;
|
||||||
style.value = {top: (-window.innerHeight) + 'px',left:0};
|
style.value = {top: (-window.innerHeight) + 'px',left:0};
|
||||||
popper.value.remove();
|
// popper.value.remove();
|
||||||
// visible.value = false;
|
visible.value = false;
|
||||||
innnerPosition.value = props.position;
|
innnerPosition.value = tempPosition.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件绑定
|
// 事件绑定
|
||||||
// on(props.el, triggerArr[0], doShow);
|
on(props.el, triggerArr[0], doShow);
|
||||||
on(triggerArr[1]??props.el, triggerArr[2], doHidden);
|
on(triggerArr[1]??props.el, triggerArr[2], doHidden);
|
||||||
checkTarget.value = triggerArr[3];
|
checkTarget.value = triggerArr[3];
|
||||||
|
|
||||||
// 计算位置显示
|
// 计算位置显示
|
||||||
const showPosistion = function(){
|
const showPosistion = function(){
|
||||||
postionFns[props.position] && (style.value = postionFns[props.position](props.el, popper.value, innnerPosition));
|
postionFns[tempPosition.value] && (style.value = postionFns[tempPosition.value](props.el, popper.value, innnerPosition));
|
||||||
}
|
}
|
||||||
|
onMounted(()=>{
|
||||||
// 节点变化, 获取当前实例对应的dom, 如果为显示状态,则计算位置显示
|
|
||||||
const nodeChange = function(){
|
|
||||||
popper.value = getCurrentInstance()?.vnode.el;
|
|
||||||
visible.value && (popper.value.offsetWidth === 0 ? setTimeout(showPosistion, 0) : showPosistion());
|
visible.value && (popper.value.offsetWidth === 0 ? setTimeout(showPosistion, 0) : showPosistion());
|
||||||
}
|
})
|
||||||
onMounted(nodeChange)
|
|
||||||
onUpdated(nodeChange)
|
|
||||||
</script>
|
</script>
|
@ -1,4 +1,4 @@
|
|||||||
import { h, render} from "vue";
|
import { h, ref, render, watchEffect} from "vue";
|
||||||
import popper from "./index.vue";
|
import popper from "./index.vue";
|
||||||
import { once } from "../../tools/domUtil";
|
import { once } from "../../tools/domUtil";
|
||||||
const EVENT_MAP : any = {
|
const EVENT_MAP : any = {
|
||||||
@ -9,16 +9,24 @@ const usePopper = {
|
|||||||
createPopper(el: HTMLElement, props: any, trigger : string) {
|
createPopper(el: HTMLElement, props: any, trigger : string) {
|
||||||
const _this = this;
|
const _this = this;
|
||||||
once(el, EVENT_MAP[trigger], () => {
|
once(el, EVENT_MAP[trigger], () => {
|
||||||
const _props = {...props};
|
// TODO 临时解决方案
|
||||||
_props.el = el;
|
const _props:any = {el};
|
||||||
|
for (const key in props) {
|
||||||
|
_props[key] = ref(props[key]);
|
||||||
|
}
|
||||||
_this.renderPopper(_props);
|
_this.renderPopper(_props);
|
||||||
|
watchEffect(() => {
|
||||||
|
for (const key in _props) {
|
||||||
|
_props[key].value = props[key];
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
renderPopper(props: any) {
|
renderPopper(props: any) {
|
||||||
const container: HTMLDivElement = document.createElement("div");
|
const container: HTMLDivElement = document.createElement("div");
|
||||||
// container.setAttribute("class", "lay-div");
|
// container.setAttribute("class", "lay-div");
|
||||||
const node = h(popper, props);
|
const node = h(popper, props);
|
||||||
render(h(popper, props), container);
|
render(node, container);
|
||||||
container.firstElementChild && document.body.appendChild(container.firstElementChild);
|
container.firstElementChild && document.body.appendChild(container.firstElementChild);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import usePopper from "../popper/usePopper";
|
import usePopper from "../popper/usePopper";
|
||||||
import { on } from "../../tools/domUtil";
|
import { defineComponent} from "vue";
|
||||||
import { defineComponent, h, render} from "vue";
|
|
||||||
import popper from "../popper/index.vue";
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "LayTooltip",
|
name: "LayTooltip",
|
||||||
props: {
|
props: {
|
||||||
@ -17,6 +15,10 @@ export default defineComponent({
|
|||||||
isDark: {
|
isDark: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
@ -25,12 +27,8 @@ export default defineComponent({
|
|||||||
mounted() {
|
mounted() {
|
||||||
const _this = this;
|
const _this = this;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
on(_this.$el, 'mouseenter', () => {
|
usePopper.createPopper(_this.$el, _this.$props, 'hover')
|
||||||
const container: HTMLDivElement = document.createElement("div");
|
|
||||||
render(h(popper, {...this.$props, el: this.$el}), container);
|
|
||||||
container.firstElementChild && document.body.appendChild(container.firstElementChild);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user