为什么不能定义计算样式属性的访问器描述符?

Cha*_*ark 5 html javascript

我想通过display属性的变化来检测CSS 属性的值变化class,我想出了下面的代码片段。

我知道getComputedStyle返回一个只读的活动CSSStyleDeclaration对象,但是当元素的样式改变时对象会自动更新,我假设它以某种方式分配了它的属性。

但它没有调用 getter 和 setter。为什么会发生这种情况,然后它在只读时如何分配其属性?

let parent = document.querySelector(".parent");
let child = parent.querySelector(".child");
let style = getComputedStyle(child);

let display = Symbol("display");
style[display] = style.display;

Object.defineProperty(style, "display", {
  get() {
    console.log("getter");
    return style[display];
  },
  set(value) {
    console.log("setter", value);
    style[display] = value;
  }
});

let button = document.querySelector("button");
button.addEventListener("click", () => {
  child.classList.toggle("hide");
});
Run Code Online (Sandbox Code Playgroud)
.child {
  height: 100px;
  background-color: #80a0c0;
}

.hide {
  display: none;
}
Run Code Online (Sandbox Code Playgroud)
<button>Toggle</button>
<div class="parent">
  <div class="child"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 2

主机提供的对象不需要玩得很好。:-)(嗯,即使是主机提供的对象也有一些要求。)

尽管在 Chrome 和相关对象上,该对象声称该display属性是一个简单的数据属性(在 Firefox 和 Legacy Edge 上,它更合理,是原型上的访问器属性):

let style = getComputedStyle(document.querySelector(".child"));
let kind = "own";
do {
    const descr = Object.getOwnPropertyDescriptor(style, "display");
    if (descr) {
        console.log(kind + " property:", descr);
        break;
    }
    if (kind === "own") {
        kind = "prototype";
    } else {
        kind += "'s prototype";
    }
    style = Object.getPrototypeOf(style);
} while (style);
Run Code Online (Sandbox Code Playgroud)
.child {
  height: 100px;
  background-color: #80a0c0;
}

.hide {
  display: none;
}
Run Code Online (Sandbox Code Playgroud)
<button>Toggle</button>
<div class="parent">
  <div class="child"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

……这是说谎。:-)(在 Chrome 上。)您成功地在对象上创建了一个访问器属性,然后该对象停止反映对该display元素的基础属性的更改(因为它只是更新您用符号命名的属性):

let parent = document.querySelector(".parent");
let child = parent.querySelector(".child");
let style = getComputedStyle(child);

let display = Symbol("display");
style[display] = style.display;

Object.defineProperty(style, "display", {
  get() {
    console.log("getter");
    return style[display];
  },
  set(value) {
    console.log("setter", value);
    style[display] = value;
  }
});

let button = document.querySelector("button");
button.addEventListener("click", () => {
  child.classList.toggle("hide");
  console.log("style.display: " + style.display);
});
Run Code Online (Sandbox Code Playgroud)
.child {
  height: 100px;
  background-color: #80a0c0;
}

.hide {
  display: none;
}
Run Code Online (Sandbox Code Playgroud)
<button>Toggle</button>
<div class="parent">
  <div class="child"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

您可以使用以下命令复制相同的行为Proxy

const realStyle = {
    display: "block"
};
const style = new Proxy(realStyle, {
    get(target, propName) {
        return target[propName];
    },
    set(target, propName, value, receiver) {
        if (propName in target) {
            return;
        }
        return Reflect.set(target, propName, value, receiver);
    }
});

console.log("descriptor for `display`:");
console.log(Object.getOwnPropertyDescriptor(style, "display"));

console.log("style.display = " + style.display);
console.log("Setting it to 'none'");
style.display = "none";
console.log("style.display = " + style.display);

const d = Symbol("display");
style[d] = style.display;
Object.defineProperty(style, "display", {
    get() {
        console.log("getter");
        return style[d];
    },
    set(value) {
        console.log("setter");
        style[d] = value;
    }
});

console.log("style.display = " + style.display);
console.log("Setting it to 'none'");
style.display = "none";
console.log("style.display = " + style.display);
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper {
    max-height: 100% !important;
}
Run Code Online (Sandbox Code Playgroud)