• Author: Chen Da Yu Tou
  • Making: KRISACHAN

I don’t know if you’ve seen waiting for Godot, the famous absurd play. The plot is about ggo and Didi waiting for Godot in the process of some trivia, a total of two acts. After all these years of waiting, I don’t know where Gordo is now, if he showed up.

If Gogo and Didi were listening for Godot the way we listen for page elements, wouldn’t there be a state of empty joy? Don’t you have to wait so hard? Maybe even go after Gordo?

Speaking of listening for page element changes, do you know of any ways to do this?

Object.defineProperty

The Object. DefineProperty attribute is something you should be familiar with (after all, you are a regular user of all kinds of blogs), but a brief introduction

Object.defineproperty allows you to precisely add or modify attributes of an Object. Ordinary properties added through assignment operations are enumerable and can be rendered during property enumeration.

Key values that the descriptor can have at the same time:

configurable enumerable value writable get set
Data descriptor Yes Yes Yes Yes No No
Access descriptor Yes Yes No No Yes Yes

So we have the following effect:

The code is as follows:

'use strict'
Object.defineProperty(godot, 'style', {
    get() {
        return this.getAttribute('style')},set(data) {
        this.setAttribute('style', data)
        const distance = (noLeftTree.offsetLeft - this.offsetLeft)
        console.log(distance >= 51 ? 'Gordo's not here. Let's do our jobs.' : 'Godot's almost there. Let's go. Let's get together.')}})const whereIsGodot = start= > {
    if (start) {
        let d = 0
        const godotRun = () = > {
            if (noLeftTree.offsetLeft - 51 >= d) {
                setTimeout(() = > {
                    d++
                    godot.style = `left: ${d}px`
                    godotRun()
                }, 16)
            }
        }
        godotRun()
    }
}
Copy the code

To put it simply, use Object.defineProperty to listen for Gordo’s position change, and then when Gordo moves near the meeting place, the two guys waiting for Gordo can go to the meeting place. From the above code, we can see that the whereIsGodot function is only responsible for godot’s position movement, but the listening rights are with the two people waiting for Godot, ensuring that the code is semantically coupled as little as possible.

MutationObserver

Mmmmm, I thought MutationObserver was a new property until I took an arrow in the knee and saw Can I use.

I didn’t know it existed either, but I learned about it recently when I was working on a situation where I needed to listen for changes in page elements.

So fishhead looked at the documentation and found a great API.

So what is it?

This is an API that listens for changes in the DOM Tree.

As defined by the WHATWG, its execution logic is as follows:

  1. Execute the listening microtask queue first;
  2. After executing the microtask queue, the monitored record is encapsulated into an array for processing.
  3. The processing result is then returned.

So how do you use it?

The mutation observer is a constructor that accepts a callback and returns a list of node records (sequence

) and the constructed parameter object (MutationObersver).

It has the following three methods:

  1. Observe (target, options) : Monitor object. Accept two parameters: target and options.
  2. Disconnect () : Disconnects the listening function;
  3. TakeRecords () : Clears the listening queue and returns the result.

Options This parameter is optional (the following properties can be set to true) :

  1. ChildList: monitors changes to target child nodes.
  2. Attributes: Listens for changes to target attributes
  3. CharacterData: Listens for changes to target data;
  4. Subtree: Listens for changes in the target and its descendants
  5. AttributeOldValue: Specifies the value before the target attribute changes.
  6. CharacterDataOldValue: Specifies the value before the target data is changed.
  7. AttributeFilter: A list of attributes that do not need to be listened on (this attribute is added to the filter attribute list).

How do we monitor Gordo’s location?

Let’s listen for godot’s position change through actual code.

The effect is the same as above.

The code is as follows:

const godot = document.querySelector('#godot')
const config = {
    childList: true.attributes: true.characterData: true.subtree: true.attributeOldValue: true.characterDataOldValue: true
}
const mutationCallback = mutationsList= > {
    const[{target: {
                offsetLeft: godotPos
            }
        }
    ] = mutationsList
    const distance = (noLeftTree.offsetLeft - godotPos)
    console.log(distance >= 51 ? 'Gordo's not here. Let's do our jobs.' : 'Godot's almost there. Let's go. Let's get together.')}const observer = new MutationObserver(mutationCallback)
observer.observe(godot, config)
const whereIsGodot = start= > {
    if (start) {
        let d = 0
        const godotRun = () = > {
            if (noLeftTree.offsetLeft - 51 >= d) {
                setTimeout(() = > {
                    d++
                    godot.style = `left: ${d}px`
                    godotRun()
                }, 16)}else {
                observer.disconnect()
            }
        }
        godotRun()
    }
}
Copy the code

Because fishhead business needs to monitor data changes in part of a function that has been perfected, if the original code is changed, it is not an easy thing, and this code is too long, the coupling degree will be higher, so we choose to use mutation observer to achieve, the effect is good.

Intersection Observer

Other than listening for element changes, what other way is there to know where Gordo is?

Intersection Observer.

What is this?

Gordo thought to himself, “Another Observer? Stop listening and I’ll find you, here and now.”

IntersectionObserver literally translates as “IntersectionObserver”, and this API enables developers to listen for ways in which a target element intersects with a root (ancestor or viewport) element.

It is used similarly to MutationObserver in that it is a constructor and accepts a callback function (callback(entries)) and optional argument objects (options).

So how do you use it?

First of all, the callback returns a listening attribute object (IntersectionObserverEntry), its specific attributes is as follows:

  1. Time: the time at which visibility changes, a double-precision millisecond timestamp;
  2. RootBounds: Box area information for the root element, returned if there is a root elementgetBoundingClientRect()Is returned if nonull;
  3. BoundingClientRect: Listens for the element’s box area information;
  4. IntersectionRect: monitors the intersecting area information of elements and root elements;
  5. IsIntersecting: judge whether the listening element intersects with the root element and return a Boolean value;
  6. IntersectionRatio: visibility ratio of monitoring elements, i.eintersectionRect / boundingClientRect1 when completely visible, less than or equal to 0 when completely invisible;
  7. Target: The target element to listen on.

Options Optional parameters are as follows:

  1. Root: The root element that intersects the listener. If not, the implicit root is returned.
  2. RootMargin: the same as CSSmarginAlso, the offset of the crossover occurs;
  3. Threshold: indicates the threshold for triggering callback. Fill in an array, ranging from 0 to 1, to determine the cross ratio of listening events.

The options are as follows:

  1. IntersectionObserver. Observe () : to start listening;
  2. IntersectionObserver. Disconnect () : stop listening;
  3. IntersectionObserver. TakeRecords () : returns all the observable IntersectionObserverEntry array of objects;
  4. IntersectionObserver. Unobserve () : to makeIntersectionObserverStop listening for a specific target element.

Gordo, are you coming or not tonight?

So how do you use this API to listen for Gordo’s location?

First look at the effect (really shitty)

The code is as follows:

<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    html.body {
        width: 100%;
        height: 200%;
    }
    noLeftTree {
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100px;
        background: #FFF;
    }
    godot,
    estragon,
    vladimir {
        position: absolute;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        border: 1px solid;
        text-align: center;
    }
    estragon {
        top: 0;
        left: 0;
    }
    vladimir {
        top: 0;
        right: 0;
    }
    godot {
        left: calc(50% - 25px);
        top: 1000px;
    }
</style>
<noLeftTree id="noLeftTree">
    <estragon id="estragon">go-go</estragon>
    <vladimir id="vladimir">DE DE</vladimir>
</noLeftTree>
<godot id="godot">godot</godot>
<script>
    'use strict'
    const godot = document.querySelector('#godot')
    const noLeftTree = document.querySelector('#noLeftTree')
    const ioCallback = entries= > {
        console.log(entries[0].intersectionRatio <= 0 ? 'Gordo's not here. Let's do our jobs.' : 'Godot's almost there. Let's go. Let's get together.')}const ioConfig = {
        threshold: [0.0.25.0.5.0.75.1]}const io = new IntersectionObserver(ioCallback, ioConfig)
    io.observe(godot)
</script>
Copy the code

Afterword.

In fact, if you take the time to research and make good use of the above three apis, you can achieve a lot of interesting effects. The above is just a first taste of the DEMO, but there are many important functions that can be implemented in the project.

But Gorgo and Didi had been waiting for Gordo for nearly seventy years, like a girl in love waiting for a man who cheated and played with women’s feelings.

Gordo thought to himself, “I’m just lost, here he is.”

If you like to discuss technology, or have any comments or suggestions on this article, you are welcome to add yu Tou wechat friends to discuss. Of course, Yu Tou also hopes to talk about life, hobbies and things with you. His wechat id is krisChans95