Simple Realization of Background Picture Fragment Animation

One day, by coincidence, I saw an article and was deeply fascinated by it. brucelyy: Learn another trick to be a beautiful woman (But it's 404 already)
Then spend a few days to encapsulate it, the level is limited, so the title is concise! Ugly!!! Version!!!
First of all, we use the picture of the goddess.

First, basic framework construction

Let's first look at how the basic framework works.

<!DOCTYPE HTML>
<html>

    <head>
        <title>My Goddess</title>
        <style>
            html {
                overflow: hidden;
            }

            #wrapper {
                width: 40rem;
                height: 25rem;
                position: relative;
                margin: 20px auto;
            }

            #wrapper div {
                background-image: url("http://b-ssl.duitang.com/uploads/item/201801/14/20180114134621_auNRE.jpeg");
                background-repeat: no-repeat;
                background-size: 40rem auto;
                position: absolute;
                width: 40rem;
                height: 40rem;
            }
        </style>
    </head>

    <body>
        <button id="button" type="button">Click on Beauty</button>
        <div id="wrapper">
            <div></div>
        </div>
    </body>

</html>

Now let's step by step analyze the main code functions:
html {overflow: hidden;}// jitter caused by hidden scrollbars
The key layout that can be achieved is the following code:

#wrapper div {
    background-image: url("http://b-ssl.duitang.com/uploads/item/201801/14/20180114134621_auNRE.jpeg");
    background-repeat: no-repeat;
    background-size: 40rem auto;
    position: absolute;
    width: 40rem;
    height: 40rem;
}

If the following fragmentation cannot be completed without absolute positioning,
From this, we can also find the current problems of the rudimentary version. First, we must use the background map to realize it.
The second problem caused by the background image: the size of height and width should be set
There's nothing else to say. Now the html + part comes out.

Second, Javascript implementation

In fact, the principle is not complicated, that is, to generate multiple small elements to locate screenshots separately, and then through the expansion, rotation, deformation, transparency and other effects to show in time difference. Here we directly use three attributes to control a class matching control effect.
Generating time difference:

// Generating Random Time Difference
function Random(start, end) {
  return Math.random() * (end - start) + start;
}

The effect is similar to Sprite image by splitting several small fragments and recording the current position to locate the image position.

// Divide several small pieces and record the current position to locate the position of the image, making a Sprite-like effect.
for (var i = 0; i < r; i++) {
  for (var j = 0; j < c; j++) {
    var _div = document.createElement('div');
    var _left = j * w, _top = i * h;
    _div.style.Text = 'width:' + w + 'px;height:' + h + 'px;left:' + _left + 'px;top:' + _top + 'px; opacity:0;background-position:' + (-_left) + 'px ' + (-_top) + 'px';
    _div.style.transition = 'all ' + Random(1, 1.8) + 's  ease';
    _div.style.transform = 'perspective(800px) translate3d(' + Random(-200, 200) + 'px, ' + Random(-200, 200) + 'px,300px) rotate(' + Random(-90, 90) + 'deg) scale(' + Random(0, 2) + ')'
    box.appendChild(_div);
  }
}

Because inserting separately in this way is too performance-intensive, I create a lot of insertion through characters.
It can also be found that the current problem of the rudimentary version is three: the performance loss is large, temporary ideas can consider canvas, but I do not study much, first use string to solve the problem;

Key styles of triggering:

#div.set div {
    opacity: 1 !important;
    transform: perspective(800px) translate3d(0px, 0px, 0px) rotate(0deg) scale(1) !important;
    -moz-transform: perspective(800px) translate3d(0px, 0px, 0px) rotate(0deg) scale(1) !important;
    -webkit-transform: perspective(800px) translate3d(0px, 0px, 0px) rotate(0deg) scale(1) !important;
}

The good thing about this is that it's triggered by style control rather than js, which saves a lot of time.

Third, finally began to encapsulate

Here I am writing in more detail on the basis of improving my personal writing level and friendly attitude towards novices. The veteran can just skip to the bottom of the code.
Now you should all understand the principle, or to save time, I directly encapsulated it with jQuery, the conventional steps first write an outer layer:

$(function($) {
    //Default configuration
    var defaults = {
    };
}(jQuery));

Then the previous time difference function can be attached to the kernel directly as a plug-in of the global function in jQuery. Conventional configurations can be: trigger elements, number of columns, animation time, delay time and class names to control animation.

$(function ($) {

  //Default configuration
  var defaults = {
    className: 'explode',//Control class name
    button: null, //Trigger button
    lines: 5, //Segmented rows
    rows: 5, //Segmented column
    delay: 0, //ms, automatic execution time of animation, default 300 milliseconds, 0 is not triggered
    time: [1, 1.8], //Animation Time Range
  };

  $.fn.explode = function (options) {

    //Keeping this pointing, there is no need to wrap this in a $number, such as $(this), because this is already a jQuery object.
    var $self = this,
      _explode = {

        //Initialization
        init: function () {

          //conditions for execution
          options = $.extend(defaults, options);

        },

      }

    // Generating Random Time Difference
    $.Random = function (start, end) {
      return Math.random() * (end - start) + start;
    }
  }(jQuery))

There are some code snippets worth mentioning: var $self = this, which I thought should be var $self = this. In fact, this is to point to trigger objects, such as $(' div').explode().
So here this ==$('#div')?
Actually not. Even if the content is the same, it actually points to different stacks, so they are not the same. For more details, please refer to the notes I wrote earlier. Basic Types and Reference Types

This is a configurable item. If you don't know how to use it, you can Baidu it. Generally speaking, it will merge into an object and cover the front with the same configuration.
options = $.extend(defaults, options);

The original batch insertion dom element is modified as follows:

// Generating DOM
createDom: function() {
  var i = 0,
    j = 0,
    width = $self.width(),
    height = $self.height(),
    w = width / options.lines,
    h = height / options.rows,
    str = '';

  // Cutting debris
  for (; i < options.rows; i++) {
    for (j = 0; j < options.lines; j++) {
      //Fill in screenshot animation
      var _left = j * w,
        _top = i * h;

      str += "<div style='width:" + w + "px;\
                        height:" + h + "px;\
                        left:" + _left + "px;\
                        top:" + _top + "px;\
                        opacity:0;\
                        background-position:" + (-_left) + "px " + (-_top) + "px;\
                        transition:all " + $.Random(options.time[0], options.time[1]) + "s ease;\
                        transform:perspective(" + width + "px) translate3d(" + $.Random(-w, w) + "px, " + $.Random(-w, w) + "px,300px) rotate(" + $.Random(-90, 90) + "deg) scale(" + $.Random(0, 2) + ")'></div>"
    }
  };

  return str;
}

Because there are no difficulties, let's not say, I believe everyone can see clearly.

Considering that plug-ins are best able to solve most of the problems, users can complete the effect as long as they call, so I add the control style dynamically.


//Add as Style
addStyle: function () {
    var $style = $('style'),
        _w = $self.width(),
        _style = '#wrapper div {background-image:url(' + $self.attr('data-img') + ')}\
                #wrapper.' + options.className + ' div {\
                    opacity: 1!important;\
                    transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                    -moz-transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                    -webkit-transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                }';

    //Added text to existing style areas, otherwise added
    $style.length
        ? $style.append(_style)
        : $('<style />')
            .text(_style)
            .appendTo('body');
}

And the trigger elements mentioned above, bind and unbind

//binding
bind: function() {
    //If there are trigger elements
    if(options.button) $(options.button).click(function() {
        $self.toggleClass(options.className);
    })
},

//Remove bindings
destroy: function() {
    $(options.button).unbind('click')
},

Adding an automated execution is almost like a chain call, so init changes to this

//Initialization
init: function() {

    //conditions for execution
    options = $.extend(defaults, options);

    //Add Homing Style
    this.addStyle();

    //Batch Rendering DOM
    $self.append(this.createDom());

    //binding
    this.bind();

    //If there is an automatic execution requirement, default 300
    if(options.delay) setTimeout(function() {
        $self.addClass(options.className);
    }, options.delay)

    //call chaining
    return this;
},

The invocation method is as follows:

$(function() {
    $('#wrapper').explode({
        className: 'explode',
        button: $('#button'),
        lines: 5,
        rows: 5,
        delay: 300,
        time: [1, 2]
    });
})

Well, that's all for the rudimentary version. Here's the complete code:

<!DOCTYPE HTML>
<html>

    <head>
        <title>Beauty</title>
        <style>
            html {
                overflow: hidden;
            }

            #wrapper {
                width: 500px;
                height: 500px;
                position: relative;
                margin: 20px auto;
            }

            #wrapper div {
                background-repeat: no-repeat;
                background-size: 40rem auto;
                position: absolute;
                width: 100px;
                height: 100px;
            }

            #button{
                position: relative;
                z-index: 10;
            }
        </style>
    </head>

    <body>
        <button id="button" type="button">Click on Beauty</button>
        <div id="wrapper" data-img='http://b-ssl.duitang.com/uploads/item/201801/14/20180114134621_auNRE.jpeg'></div>

        <script src="https://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script>
            $(function ($) {

                //Default configuration
                var defaults = {
                    className: 'explode', //Control class name
                    button: null, //Trigger button
                    lines: 5, //Segmented rows
                    rows: 5, //Segmented column
                    delay: 0, //ms, automatic execution time of animation, default 300 milliseconds, 0 is not triggered
                    time: [
                        1, 1.8
                    ], //Animation Time Range
                };

                $.fn.explode = function (options) {
                    //Keeping this pointing, there is no need to wrap this in a $number, such as $(this), because this is already a jQuery object.
                    var $self = this,
                        _explode = {

                            //Initialization
                            init: function () {

                                //conditions for execution
                                options = $.extend(defaults, options);

                                //Add Homing Style
                                this.addStyle();

                                //Batch Rendering DOM
                                $self.append(this.createDom());

                                //binding
                                this.bind();

                                //If there is an automatic execution requirement, default 300
                                if (options.delay) 
                                    setTimeout(function () {
                                        $self.addClass(options.className);
                                    }, options.delay)

                                    //call chaining
                                return this;
                            },

                            //binding
                            bind: function () {
                                //If there are trigger elements
                                if (options.button) 
                                    $(options.button).click(function () {
                                        $self.toggleClass(options.className);
                                    })
                            },

                            //Remove bindings
                            destroy: function () {
                                $(options.button).unbind('click')
                            },

                            //Generating DOM
                            createDom: function () {
                                var i = 0,
                                    j = 0,
                                    width = $self.width(),
                                    height = $self.height(),
                                    w = width / options.lines,
                                    h = height / options.rows,
                                    str = '';

                                //Cutting debris
                                for (; i < options.rows; i++) {
                                    for (j = 0; j < options.lines; j++) {
                                        //Fill in screenshot animation
                                        var _left = j * w,
                                            _top = i * h;

                                        str += "<div style='width:" + w + "px;\
                                                    height:" + h + "px;\
                                                    left:" + _left + "px;\
                                                    top:" + _top + "px;\
                                                    opacity:0;\
                                                    background-position:" + (-_left) + "px " + (-_top) + "px;\
                                                    transition:all " + $.Random(options.time[0], options.time[1]) + "s ease;\
                                                    transform:perspective(" + width + "px) translate3d(" + $.Random(-w, w) + "px, " + $.Random(-w, w) + "px,300px) rotate(" + $.Random(-90, 90) + "deg) scale(" + $.Random(0, 2) + ")'></div>"
                                    }
                                };

                                return str;
                            },

                            //Add as Style
                            addStyle: function () {
                                var $style = $('style'),
                                    _w = $self.width(),
                                    _style = '#wrapper div {background-image:url(' + $self.attr('data-img') + ')}\
                                            #wrapper.' + options.className + ' div {\
                                                opacity: 1!important;\
                                                transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                                                -moz-transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                                                -webkit-transform: perspective(' + _w + ') translate3d(0px, 0px, 0px) rotate(0deg) scale(1)!important;\
                                            }';

                                //Added text to existing style areas, otherwise added
                                $style.length
                                    ? $style.append(_style)
                                    : $('<style />')
                                        .text(_style)
                                        .appendTo('body');
                            }
                        }

                    //Automatic initialization
                    _explode.init();
                }

                //Random Range
                $.Random = function (start, end) {
                    return Math.random() * (end - start) + start;
                }
            }(jQuery));
        </script>
        <script>
            $(function () {
                $('#wrapper').explode({
                    className: 'explode',
                    button: $('#button'),
                    lines: 5,
                    rows: 5,
                    delay: 300,
                    time: [1, 2]
                });
            })
        </script>
    </body>

</html>

The effect comes out, and there are many disadvantages.
Question 4: Fragments do not disappear, but are hidden. It is easy to hide the interactive events of other elements, such as the buttons in the case.
Question 5: Can it be realized that in the actual website, the image fragments enter and slide down will trigger the image execution under the view, more likely to be combined with the lazy loading plug-in.

Well, for the time being, I think so much about it. Although my ability is not strong enough, it's still good to have ideas. I think it will be better if I improve it slowly in the future. Some people can communicate with each other.

Keywords: Javascript JQuery SSL

Added by mouloud2001 on Thu, 01 Aug 2019 05:11:42 +0300