preface

For our front-end, user experience is a point we must do well in the development of customer-facing applications, how to achieve good interactive transition effects is also a technology we need to master. The author has used VUE and React. Both of these frameworks provide components for processing UI transition animations when developing applications. We do not need to care about the underlying implementation, but simply configure the API of the components to solve most of the transition scenes. But I was recently working on a component that required some special transition animations, and those components were a bit limited, so I learned and practiced the transition technique used by the aforementioned component, FLIP.

Why FLIP

For example, if there are four tags on the page [tag1, tag2, tag3, tag4], I now need to add a new tag tag5, which will become [tag5, tag1, tag2, tag3, tag4], I want to animate the first 4 tabs to move to the right. What do you think?

If I had not learned FLIP before, I would consider adding a transitional CSS to each of the four labels, and then changing the transform to move the labels to the right a certain distance, or using JS to move the labels to the right.

There are a couple of tricky problems with this approach. If you move a distance to the right, it’s ok to calculate the distance if every element has the same width and height, but if every element has the same width and height, how do you calculate the distance? If a row is full, and I need a newline, how do I calculate the height? One more question, the current front-end frameworks use data to control views. When should we add this new TAG1 to the data?

Add the data first, then control the label movement, the page will be re-rendered, the position of the label will change, and then control the label to move to the right is actually wrong.

Move first, then add data, if it is CSS control of the movement, according to the transition time, often because of js timing is not accurate occurrence of frame hopping phenomenon. If the movement is controlled by JS, it usually needs to wait for all element movement callbacks to complete before adding data.

FLIP implementation Principle

FLIP is a contraction of four words: First, Last, Invert and Play. I don’t like to write specific concepts in digs. Everyone comes to the blog to learn technology. If you are interested in specific concepts, you can learn about them by yourself.

FLIP is actually A reverse transition idea. The general transition idea is that WHEN I need to move an element from point A to point B, I need to modify the transform of this element A little bit to make it reach point B. FLIP takes the element directly to point B, calculates the distance between point A and point B, and sets the transform to move it from point A to translate(0px, 0px).

Here’s how the FLIP works

  • 1. Record the original DOM node coordinates
  • 2. Data changes, dom page modification (add, delete, reorder)
  • 3. Record the coordinates of the new DOM point
  • 4. According to the old and new coordinates, obtain the distance between the two coordinates
  • 5. Add an initial style to the dom that has been re-rendered and animate it like a transition

preview

I wrote a sample page modeled after the example in the transition component on the VUE website. Since FLIP is just an idea for animation, not a framework, I used native JS for my demo pages.

The DEMO page

Implementation details

Here are the implementation steps and details of the sample page I wrote. First, the layout, which is simple, is a Flex container.

.item_box {
    display: flex; flex-wrap: wrap; . } .item { ... }// List of data, which is modified synchronously every time a page element is modified
const itemList = [10.9.8.7.6.5.4.3.2.1];
// Initialize and render the item list
const itemInit = () = > {
  const fragment = document.createDocumentFragment();
  for (let i = 0; i < itemList.length; i ++) {
    const dom = document.createElement('div');
    // The last item here is to find the corresponding DOM element later
    dom.className = `item item${itemList[i]}`;
    dom.innerHTML = itemList[i];
    fragment.appendChild(dom);
  }
  document.querySelector('.item_box').appendChild(fragment);
};

itemInit();
Copy the code

Taking the new element as an example, we implemented the first step of FLIP, recording the coordinates of the original DOM node

const getLeftOrTops = () = > {
  const rectList = [];
  // Iterate over the list of data
  for (let i = 0; i < itemList.length; i ++) {
    // Calculate the left and top data for these nodes
    const { left, top } = document.querySelector(`.item${itemList[i]}`).getBoundingClientRect()
    rectList.push({ left, top });
  }
  return rectList;
};
Copy the code

The second step, data changes, modifies the DOM page, and the third step, records the coordinates of the new DOM points.

let count = 10;
// Add the dom node method
const itemAdd = () = > {
  // This is the way to record the original DOM node coordinates
  const oldRects = getLeftOrTops();
  const curIndex = count++;
  // Add a new element to the data list
  itemList.unshift(curIndex);
  // Insert the new node in the page to modify the DOM page
  $box.insertBefore(createItem(curIndex), $box.childNodes[0]);
  // Step 3, record the coordinates of the new DOM point
  // Get the coordinates of the DOM nodes in the new data list
  // New DOM nodes do not need to add transition conditions, other old and new DOM nodes need to calculate the difference between the old and new coordinates
  const newRects = getLeftOrTops().slice(1);
};
Copy the code

There’s a critical point here, if you’re invueandreactIs the order in which the page DOM is modified and the coordinates of the new DOM nodes are obtained. If thevueTo modify a DOM page is to modify data,vueThe page DOM modification operation is stored innextTick, wait until the current macro task runs, and then run in the micro task. Therefore, the method to obtain the coordinates of the new DOM node must also be written innextTickIs guaranteed to be retrieved after the DOM element has been modified (the page has not actually been re-rendered, but the DOM node has been modified). inreactRecommended use inuseLayoutEffectGet the coordinates of the new DOM nodes after data changes and DOM modifications.

Then we continued the FLIP process

const itemAdd = () = > {
   // The above content is omitted.for (let i = 0; i < oldRects.length; i ++) {
        // Calculate the distance between the two coordinates based on the old and new coordinates
        const left = oldRects[i].left - newRects[i].left;
        const top = oldRects[i].top - newRects[i].top;
        const move = [
          { transform: `translate(${left}px, ${top}px)` },
          { transform: "translate(0)"},];const dom = document.querySelector(`.item${oldRects[i].key}`);
        // Here we use the Animate method of the Web API to move elements
        You can use Polyfill, or use other JS animation libraries
        // Add an initial style to the dom that has been re-rendered so that it has a transition-like animation
        dom && dom.animate(move, {
          duration: 300.easing: "Cubic - the bezier (,0,0.4 0, 1)"}); }};Copy the code

That’s it. We’re done with the FLIP process, and your new element has a nice transition animation.

The complete code for additions, deletions, and rearrangements can be found in the sample page above.

conclusion

FLIP is just an idea for transitioning animations, not only for document flow scenarios like the one above, but also for absolutely positioned layouts. And it’s a very flexible approach, not limited to the content in this article. Think about using FLIP to help you solve your problems more easily when implementing interactive effects.

Thank you

If this article helped you, please give it a thumbs up. Thank you!