首页 > 解决方案 > 为什么 get 属性的工作方式与 Vue 中的函数不同,看起来我必须使用函数而不是 getter 一些未知的幕后原因

问题描述

这会返回错误的值

    get scrollTop() {
        return window.pageYOffset || document.documentElement.scrollTop
    }

但是这个

    scrollTop() {
        return window.pageYOffset || document.documentElement.scrollTop
    }

按预期工作,这是 Vue 或 typescript 或其 javascript 中的一些隐藏的宝石吗?当我不知何故无法解释为什么有时它们不起作用时,我不知道现在如何依赖语法更易读的属性,从而导致我的开发速度变慢,因此始终使用函数更可靠。我可以期待更多这样的情况吗?

<template>
    <div :style="computedStyle" class="tooltip">
        <div ref="tooltip-background" v-html="svg" class="tooltip-background"/>
        <div class="tooltip-content">
            <div v-if="nearestItem" class="tooltip-content-values">
                <span class="">{{getChartTitle(nearestItem)}}: </span>
                <span class="tooltip-content-values-value">{{nearestItem.value}}</span>
            </div>
            <div class="tooltip-content-date">{{date}}</div>
        </div>
    </div>
</template>

<style scoped>
    .tooltip {
        pointer-events: none;
        position: absolute;
        width: 300px;
    }

    .tooltip-background {
        width: 300px;
        position: absolute;
        z-index: 1
    }

    .tooltip-content {
        position: absolute;
        z-index: 2;
        margin-left: 25px;
        margin-top: 3px;
        padding: 15px;
    }

    .tooltip-content-values {
        margin-top: 2px;
        font-family: Work Sans, sans-serif;
        font-style: normal;
        font-weight: normal;
        font-size: 16px;
        line-height: 20px;
        color: #666666;
    }

    .tooltip-content-values-value {
        font-family: Work Sans, sans-serif;
        font-style: normal;
        font-weight: normal;
        font-size: 16px;
        line-height: 20px;
        color: #111111;
    }

    .tooltip-content-date {
        margin-top: 3px;
        font-family: Work Sans, sans-serif;
        font-style: normal;
        font-weight: 500;
        font-size: 12px;
        line-height: 24px;
        color: #666666;
        opacity: 0.5;
    }
</style>

<script lang="ts">
    import {Component, Vue} from "vue-property-decorator"
    import {BMChartData, BMChartTooltipType, ChartTooltipModel} from "@/components/charts/ChartTypes";
    import Chart, {ChartTooltipItem} from "chart.js";
    import {is, log, stringify} from "@/extensions/CSLang";
    import {CSPoint} from "@/extensions/CSPoint";

    @Component
    export default class BMChartTooltip extends Vue implements BMChartTooltipType {

        chart: Vue | null = null
        model: ChartTooltipModel | null = null
        data: BMChartData | null = null
        lastHover: MouseEvent | null = null
        svg = require(`@/assets/img/icons/tooltip-background.svg`)
        date: String = "12.Jul, Tuesday, 19:10"
        nearestItem: ChartTooltipItem | null = null

        get tooltipBackground() {
            return this.$refs["tooltip-background"] as HTMLDivElement
        }

        get computedStyle() {
            return {
                left: this.tooltipLeft,
                top: this.tooltipTop,
                visibility: this.nearestItem ? "visible" : "hidden"
            }
        }

        get tooltipLeft() {
            if (this.nearestItem) return (this.scrollLeft() + this.chartRect().left + this.nearestItem.x! + 10) + "px"
            return `0px`
        }

        get tooltipTop() {
            if (this.nearestItem) return (this.scrollTop() + this.chartRect().top + this.nearestItem.y! - 42) + "px"
            return `0px`
        }

        scrollLeft() { //Cannot be getter because then returns wrong value !!!
            return window.pageXOffset || document.documentElement.scrollLeft
        }

        scrollTop() { //Cannot be getter because then returns wrong value !!!
            return window.pageYOffset || document.documentElement.scrollTop
        }

        chartRect() {
            return this.chart!.$el.getBoundingClientRect()
        }

        get items(): ChartTooltipItem[] {
            let items = Array<ChartTooltipItem>()
            if (this.model && this.model.dataPoints)
                for (let item of this.model.dataPoints)
                    if (item.x == this.model.caretX) items.push(item)
            return items
        }

        borderColor(value: string) {
            for (let element of this.tooltipBackground.children[0].getElementsByTagName("path"))
                element.setAttribute("fill", value)
        }

        onUpdate(chart: Vue, model: ChartTooltipModel, data: BMChartData): void {
            if (model && model.dataPoints && model.dataPoints!.length > 0) {
                this.chart = chart
                this.model = model
                this.data = data
                this.updateNearestItem()
            }
        }

        onHover(event: MouseEvent, activeElements: Array<{}>) {
            this.lastHover = event
            this.updateNearestItem()
            if (this.nearestItem) {
                let lineColor = this.data!.charts[this.nearestItem.datasetIndex!].lineColor
                this.borderColor(lineColor)
                this.date = this.nearestItem.label ? this.nearestItem.label : ""
            }
        }

        updateNearestItem() {
            let nearestDistance = Number.MAX_SAFE_INTEGER
            this.nearestItem = null
            for (let item of this.items) {
                let distance = new CSPoint(item.x! + this.chartRect().left, item.y! + this.chartRect().top)
                    .distance(CSPoint.fromEvent(this.lastHover!))
                if (distance < nearestDistance) {
                    nearestDistance = distance
                    this.nearestItem = item
                }
            }
        }

        getChartTitle(item: ChartTooltipItem): string {
            return this.data ? this.data.charts[item.datasetIndex!].title : ""
        }
    }

</script>

如您所见,必须将三个方法定义为函数而不是属性 scrollLeft scrollTop 和 chartRect 否则我会得到错误的值...看起来它们是从某种不同的上下文中以某种方式调用的,所以所有从文档 dom 元素中获取的值可能有这种行为的线索。

标签: javascripttypescriptvue.js

解决方案


推荐阅读