<html> <head> <title> </ title> <style> #container {padding-top: 53px; padding-bottom: 3px; border: 1px solid gray; } #container, #scroll div {width: 100px; } #scroll, #scroll div {height: 50px; } #scroll div {float: left; } #container {position: relative; overflow: hidden; } #scroll {position: absolute; top: 0px; width: 1000px; border-bottom: 1px solid gray; } </ style> <script> / * * at the end of the topic * / </ script> </ head> <body> <div id = "container"> <div id = "scroll" style = "left: 0px;"> <div style = "background: #ffc;"> page 1 </ div> <div style = "background: #fcf;"> page 2 </ div> <div style = "background: #cff;"> page 3 </ div> <div style = "background: #fcc;"> page 4 </ div> <div style = "background: #ccf;"> page 5 </ div> <div style = "background: #cfc;"> page 6 </ div> <div style = "background: #ccc;"> page 7 </ div> </ div> </ div> <script> / * * use * / </ script> </ body> </ html>
// -
component = new SimpleScroll();
component.setContainer(document.getElementById("container"));
component.setScroll(document.getElementById("scroll"));
//
decorator1 = new Decorator_PageNum();
decorator1.setComponent(component); //
//
decorator2 = new Decorator_SwitchPage();
decorator2.setComponent(decorator1); //
decorator2.init();
decorator2.nextPage();
component = new SimpleScroll();
component.setContainer(document.getElementById("container"));
component.setScroll(document.getElementById("scroll"));
component.init();
component.nextPage();
component = new AnimScroll();
component.setContainer(document.getElementById("container"));
component.setScroll(document.getElementById("scroll"));
decorator1 = new Decorator_SwitchPage(); // new Decorator_PageNum();
decorator1.setComponent(component);
decorator1.init();
decorator1.nextPage();
// Component (interface) // because of the scope, it will also set local variables and setters / getters to them - not academic, but not scary // if there is a desire to use only prototyping, then it is necessary to create local variables "in place", // and leave all functions that use them in Scroll empty function Scroll () { var container scroll; this.setContainer = function (val) { container = val; }; this.setScroll = function (val) { scroll = val; }; this.getContainer = function () { return container; }; this.getScroll = function () { return scroll; }; this.init = function () {}; // manual initialization after setting the container and scroll // this will simplify the task somewhat, since we will not need to rewrite the setters this.nextPage = function () {}; // fast forward this.prevPage = function () {}; // rewind back this.hasNextPage = function (depth) {}; // presence of the next page, or the next depth pages; default depth = 1 this.hasPrevPage = function (depth) {}; // presence of the previous page, or the following depth pages; default depth = 1 this.findPages = function () {}; // return method number of pages this.getCurPage = function () {}; // return method current page number } // ConcreteComponent (Component implementation) // easiest scrolling function SimpleScroll () { var dublicate = this; // permanent link to the object being instantiated (for working with any this) Scroll.call (this); // aggregate interface // Scroll already knows how to work with container and scroll, but nothing more - // now we need to implement (overload) all empty methods var curPage = 0; // current page (0-4) this.init = function () {}; this.nextPage = function () { if (dublicate.hasNextPage ()) { this.getScroll (). style.left = ++ curPage * -100 + "px"; } }; this.prevPage = function () { if (dublicate.hasPrevPage ()) { this.getScroll (). style.left = --curPage * -100 + "px"; } }; this.hasNextPage = function (depth) { var depth = depth || one; return curPage + depth <dublicate.findPages (); }; this.hasPrevPage = function (depth) { var depth = depth || one; return curPage - depth> = 0; }; this.findPages = function () { return this.getScroll (). getElementsByTagName ("div"). length; }; this.getCurPage = function () { return curPage; }; } // ConcreteComponent (Component implementation) // another scrolling, with animation function AnimScroll () { var dublicate = this; // permanent link to the object being instantiated (for working with any this) Scroll.call (this); // aggregate interface var curPage = 0; var curOffset = 0; // current page offset in pixels this.init = function () {}; this.nextPage = function () { if (dublicate.hasNextPage () &&! curOffset) { curPage ++; // add immediately to decorators work curOffset = 0; nextPageIterate (); } }; function nextPageIterate () { curOffset - = 10; dublicate.getScroll (). style.left = curOffset + (curPage-1) * -100 + "px"; if (curOffset> -100) { window.setTimeout (arguments.callee, 20); } else { curOffset = 0; } } this.prevPage = function () { if (dublicate.hasPrevPage () &&! curOffset) { curPage--; curOffset = 0; prevPageIterate (); } }; function prevPageIterate () { curOffset + = 10; dublicate.getScroll (). style.left = curOffset + (curPage + 1) * -100 + "px"; if (curOffset <100) { window.setTimeout (arguments.callee, 20); } else { curOffset = 0; } } this.hasNextPage = function (depth) { var depth = depth || one; return curPage + depth <dublicate.findPages (); }; this.hasPrevPage = function (depth) { var depth = depth || one; return curPage - depth> = 0; }; this.findPages = function () { return this.getScroll (). getElementsByTagName ("div"). length; }; this.getCurPage = function () { return curPage; }; } // Decorator (interface) // can encapsulate (save to a local component variable) a component or another decorator // and just passes method calls to the component (except setComponent and getComponent) function Decorator () { var component; this.setComponent = function (val) { component = val; }; this.getComponent = function () { return component; }; this.setContainer = function (val) { return component.setContainer (val); }; this.setScroll = function (val) { return component.setScroll (val); }; this.getContainer = function () { return component.getContainer (); }; this.getScroll = function () { return component.getScroll (); }; this.init = function () { return component.init (); }; this.nextPage = function () { return component.nextPage (); }; this.prevPage = function () { return component.prevPage (); }; this.hasNextPage = function (depth) { return component.hasNextPage (depth); }; this.hasPrevPage = function (depth) { return component.hasPrevPage (depth); }; this.findPages = function () { return component.findPages (); }; this.getCurPage = function () { return component.getCurPage (); }; } Decorator.prototype = new Scroll (); Decorator.prototype.constructor = Decorator; // ConcreteDecorator (implementation of Decorator) // buttons to switch pages function Decorator_SwitchPage () { var dublicate = this; // permanent link to the object being instantiated (for working with any this) // connect the Decorator and write down references to the methods that are defined in Decorator's "interface" and which will be overridden here Decorator.call (this); var methods = { nextPage: this.nextPage, prevPage: this.prevPage, init: this.init }; var buttonNext, buttonPrev; this.init = function () { dublicate.getContainer (). appendChild (buttonPrev = createButton ("<", dublicate.prevPage)); dublicate.getContainer (). appendChild (buttonNext = createButton (">", dublicate.nextPage)); buttonNext.disabled =! dublicate.hasNextPage (); buttonPrev.disabled =! dublicate.hasPrevPage (); return methods.init (); }; this.nextPage = function () { buttonNext.disabled =! dublicate.hasNextPage (2); buttonPrev.disabled =! dublicate.hasPrevPage (-1); return methods.nextPage (); }; this.prevPage = function () { buttonNext.disabled =! dublicate.hasNextPage (-1); buttonPrev.disabled =! dublicate.hasPrevPage (2); return methods.prevPage (); }; function createButton (text, onclick) { var ret = document.createElement ("button"); ret.appendChild (document.createTextNode (text)); ret.onclick = onclick; return ret; } } // ConcreteDecorator (implementation of Decorator) // current page indicator function Decorator_PageNum () { var dublicate = this; // permanent link to the object being instantiated (for working with any this) Decorator.call (this); var methods = { nextPage: this.nextPage, prevPage: this.prevPage, init: this.init }; var text; this.init = function () { dublicate.getContainer (). appendChild (text = document.createTextNode ("...")); var ret = methods.init (); chText (); return ret; }; this.nextPage = function () { var ret = methods.nextPage (); chText (); return ret; }; this.prevPage = function () { var ret = methods.prevPage (); chText (); return ret; }; function chText () { text.nodeValue = "" + (dublicate.getCurPage () + 1) + "/" + dublicate.findPages (); } }
function cr () { var ret, last; for (var i = 0, l = arguments.length; i <l; i ++) { ret = new arguments [i] (); if (! i) { ret.setContainer (document.getElementById ("container")); ret.setScroll (document.getElementById ("scroll")); } else ( ret.setComponent (last); } last = ret; } return ret; }
<table cellpadding = "5"> <tr> <th> workWith </ th> <td> = </ td> <td> <div> <input type = "radio" name = "component" value = "simple" id = "component-simple" checked = "checked" /> <label for = "component-simple"> SimpleScroll </ label> </ div> <input type = "radio" name = "component" value = "simple" id = "component-anim" /> <label for = "component-anim"> AnimScroll </ label> </ td> <td> + </ td> <td> <input type = "checkbox" id = "pageNum" checked = "checked" /> <label for = "pageNum"> pageNum </ label> </ td> <td> + </ td> <td> <input type = "checkbox" id = "switchPage" checked = "checked" /> <label for = "switchPage"> switchPage </ label> </ td> </ tr> </ table> <button onclick = "create ();"> Recreate component with decorators </ button> <br /> <button onclick = "workWith.prevPage ();"> workWith.prevPage () </ button> <button onclick = "workWith.nextPage ();"> workWith.nextPage () </ button> <br />
var component; var decorator1; var decorator2; var workWith; function reset () { component = decorator1 = decorator2 = workWith = null; var node = document.getElementById ("scroll"); node.style.left = "0px"; while (node.nextSibling) { node.parentNode.removeChild (node.nextSibling); } } function create () { reset (); // reset previous settings (if any) // create component - basis for further work if (document.getElementById ("component-simple"). checked) { component = new SimpleScroll (); } else { component = new AnimScroll (); } component.setContainer (document.getElementById ("container")); component.setScroll (document.getElementById ("scroll")); workWith = component; if (document.getElementById ("pageNum"). checked) { // create the first decorator decorator1 = new Decorator_PageNum (); decorator1.setComponent (component); // wrap the component in the decorator workWith = decorator1; } if (document.getElementById ("switchPage"). checked) { // create another decorator decorator2 = new Decorator_SwitchPage (); if (decorator1) { // wraps the first decorator in the second decorator2.setComponent (decorator1); } else { // wrap the component in the decorator decorator2.setComponent (component); } workWith = decorator2; } workWith.init (); } create ();
Source: https://habr.com/ru/post/65219/
All Articles