代码之家  ›  专栏  ›  技术社区  ›  Ardeus

Javascript原型扩展基类无法从原型类访问基类属性/方法

  •  8
  • Ardeus  · 技术社区  · 7 年前

    我创建了一个javascript类 TkpSlider(TkpSlider) 受此启发 w3schools page . ( JSFiddle )

    var TkpSlider = function (args) {
        args= args|| {};
    };
    
    var mainSwiper = new TkpSlider();
    

    我扩展了这个功能,添加了一些来自 this page 这样我就可以在用户滑动时使用滑块。( JSFiddle )

    var TkpSwiper = function (args) {
        TkpSlider.call(this, args);
    };
    
    TkpSwiper.prototype = Object.create(TkpSlider.prototype);
    
    var mainSwiper = new TkpSwiper();
    

    我分离了代码,这样以后就不会与基本代码和任何附加函数混淆。但对于OOP,我必须通过为其创建一个新名称来进行扩展 TkpSwiper公司 ,但我想找到另一种使用相同名称的方法 TkpSlider(TkpSlider) .

    我看到了 this article 并尝试使用原型来扩展 TkpSlider(TkpSlider) 在这个 JSFiddle (下面的代码片段)。问题是我无法从子类访问基类的公共方法。虽然我测试的博客中的javascript示例工作正常,但我的代码中肯定缺少一些东西。有人能透露一些见解吗?谢谢

    var TkpSlider = function (args) {
    	args= args|| {};
        //private variable
         var btnPrev = args.btnPrev || "tkp-slide-btn-prev";//class for previous button (default: "tkp-slide-btn-prev")
        var btnNext = args.btnNext || "tkp-slide-btn-next";//class for next button (default: "tkp-slide-btn-next")
        var itemClass = args.itemClass || "tkp-slide-item"; //each item container class to slide (default: "tkp-slide-item")
        var isAutoSlide = args.isAutoSlide || false;//set auto slide (default: false)
        var autoSlideTimer = args.autoSlideTimer || 2000;//set auto slide timer when isAutoSlide is true(default: 2000)
        var hideBtnNav = args.hideBtnNav || false; //hide button navigation(default: false)
        var isRandom = args.isRandom || false; //whether next or previous slide should be random index
        var slideIndex = args.startIndex || 0; //start slide index number (zero based, index 0 = slide number 1, default :0)
    
    
        var itemNodes = document.getElementsByClassName(itemClass);
        var itemLength = itemNodes.length;
        var autoSlideInterval;
    
        //public variable
        this.testParentVar = "parent var";
    
        //init function
        init();
        function init() {
            if (itemLength > 0) {
                showSlide();
                bindEvent();
                isAutoSlide ? setAutoSlide() : "";
                hideBtnNav ? setHideBtnNav() : "";
            } else {
                throw "Cannot find slider item class";
            }
    
        }
    
    
        //private function
        function showSlide() {
            if (slideIndex >= itemLength) { slideIndex = 0; }
            if (slideIndex < 0) { slideIndex = (itemLength - 1); }
            for (var i = 0; i < itemLength; i++) {
                itemNodes[i].style.display = "none";
            }
            itemNodes[slideIndex].style.display = "block";
        }
    
        function nextPrevSlide(n) {
            slideIndex += n;
            showSlide();
        }
    
        function bindEvent() {
            var btnPrevNode = document.getElementsByClassName(btnPrev);
            if (btnPrevNode.length > 0) {
                btnPrevNode[0].addEventListener("click", function () {
    
                    if (isRandom) {
                        setRandomSlideIndex();
                    } else {
                        nextPrevSlide(-1);
                    }
    
    
                    if (isAutoSlide) {
                        clearInterval(autoSlideInterval);
                        setAutoSlide();
                    }
                });
            } else {
                throw "Cannot find button previous navigation";
            }
    
            var btnNextNode = document.getElementsByClassName(btnNext);
            if (btnNextNode.length > 0) {
                btnNextNode[0].addEventListener("click", function () {
                    if (isRandom) {
                        setRandomSlideIndex();
                    } else {
                        nextPrevSlide(1);
                    }
                    if (isAutoSlide) {
                        clearInterval(autoSlideInterval);
                        setAutoSlide();
                    }
                });
            } else {
                throw "Cannot find button next navigation";
            }
    
        }
    
        function setAutoSlide() {
            autoSlideInterval = setInterval(function () {
                if (isRandom) {
                    setRandomSlideIndex();
                } else {
                    nextPrevSlide(1);
                }
    
            }, autoSlideTimer);
        }
    
        function setHideBtnNav() {
            document.getElementsByClassName(btnPrev)[0].style.display = "none";
            document.getElementsByClassName(btnNext)[0].style.display = "none";
        }
    
        function setRandomSlideIndex() {
            var randomIndex = Math.floor(Math.random() * itemLength);
            if (randomIndex == slideIndex) {
                setRandomSlideIndex();
            } else {
                slideIndex = randomIndex;
                showSlide();
            }
        }
    
        //public function
        this.nextPrevSlide = function (n) {
            nextPrevSlide(n);
            //console.log("nextPrevSlide");
        };
    
        //getter setter
        this.setItemClass = function (prm) {
            itemClass = prm;
        };
        this.getItemClass = function () {
            return itemClass;
        };
    
    
    };
    
    //Adding touch swiper
    TkpSlider.prototype = function () {
        var self = this;
        var touchStartCoords = { 'x': -1, 'y': -1 }, // X and Y coordinates on mousedown or touchstart events.
            touchEndCoords = { 'x': -1, 'y': -1 },// X and Y coordinates on mouseup or touchend events.
            direction = 'undefined',// Swipe direction
            minDistanceXAxis = 30,// Min distance on mousemove or touchmove on the X axis
            maxDistanceYAxis = 30,// Max distance on mousemove or touchmove on the Y axis
            maxAllowedTime = 1000,// Max allowed time between swipeStart and swipeEnd
            startTime = 0,// Time on swipeStart
            elapsedTime = 0,// Elapsed time between swipeStart and swipeEnd
            //targetElement = document.getElementById('el'), // Element to delegate
            targetElements = self.getItemClass()
            ;
    
        init();
        function init() {
           
            addMultipleListeners(targetElements, 'mousedown touchstart', swipeStart);
            addMultipleListeners(targetElements, 'mousemove touchmove', swipeMove);
            addMultipleListeners(targetElements, 'mouseup touchend', swipeEnd);
        }
    
        function swipeStart(e) {
            e = e ? e : window.event;
            e = ('changedTouches' in e) ? e.changedTouches[0] : e;
            touchStartCoords = { 'x': e.pageX, 'y': e.pageY };
            startTime = new Date().getTime();
            //targetElement.textContent = " ";
        }
    
        function swipeMove(e) {
            e = e ? e : window.event;
            e.preventDefault();
        }
    
        function swipeEnd(e) {
            e = e ? e : window.event;
            e = ('changedTouches' in e) ? e.changedTouches[0] : e;
            touchEndCoords = { 'x': e.pageX - touchStartCoords.x, 'y': e.pageY - touchStartCoords.y };
            elapsedTime = new Date().getTime() - startTime;
            if (elapsedTime <= maxAllowedTime) {
                if (Math.abs(touchEndCoords.x) >= minDistanceXAxis && Math.abs(touchEndCoords.y) <= maxDistanceYAxis) {
                    direction = (touchEndCoords.x < 0) ? 'left' : 'right';
                    switch (direction) {
                        case 'left':
                            //targetElement.textContent = "Left swipe detected";
                            console.log("swipe left");
                            self.nextPrevSlide(1);
    
                            break;
                        case 'right':
                            // targetElement.textContent = "Right swipe detected";
                            console.log("swipe right");
                            self.nextPrevSlide(-1);
    
                            break;
                    }
                }
            }
        }
    
        function addMultipleListeners(el, s, fn) {
            var evts = s.split(' ');
            var elLength = el.length;
            for (var i = 0, iLen = evts.length; i < iLen; i++) {
                if (elLength > 1) {
                    for (var j = 0; j < elLength; j++) {
                        el[j].addEventListener(evts[i], fn, false);
                    }
                } else {
                    el.addEventListener(evts[i], fn, false);
                }
    
            }
        }
    }();
    
    var mainSwiper = new TkpSlider();
    .tkp-slide {
      width: 100%;
      position: relative; }
      .tkp-slide .tkp-slide-item:not(:first-child) {
        display: none; }
        .tkp-slide .tkp-slide-item img {
          width: 100%; }
      .tkp-slide .tkp-slide-btn {
        color: #fff !important;
        background-color: #000 !important;
        border: none;
        display: inline-block;
        outline: 0;
        padding: 8px 16px;
        vertical-align: middle;
        overflow: hidden;
        text-decoration: none;
        text-align: center;
        cursor: pointer;
        white-space: nowrap;
        opacity: 0.7; }
        .tkp-slide .tkp-slide-btn:hover {
          background-color: #333 !important; }
      .tkp-slide .tkp-slide-btn-prev {
        position: absolute;
        top: 50%;
        left: 0%;
        transform: translate(0%, -50%);
        -webkit-transform: translate(0%, -50%);
        -ms-transform: translate(0%, -50%); }
        .tkp-slide .tkp-slide-btn-next {
          position: absolute;
          top: 50%;
          right: 0%;
          transform: translate(0%, -50%);
          -ms-transform: translate(0%, -50%); }
    <section class="main-slide">
      <div class="tkp-slide tkp-slide--container">
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=1" alt="Slide 1" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=2" alt="Slide 2" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=3" alt="Slide 3" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=4" alt="Slide 4" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=5" alt="Slide 5" />
          </a>
        </div>
        <ul>
          <li class="tkp-slide-btn tkp-slide-btn-prev">
            &#10094;
          </li>
          <li class="tkp-slide-btn tkp-slide-btn-next">
            &#10095;
          </li>
        </ul>
      </div>
    </section>
    1 回复  |  直到 7 年前
        1
  •  8
  •   Munim Munna    7 年前

    问题1: 您没有从原型函数返回任何内容。必须将每个公共方法作为返回对象的属性返回。

    return {
      initSwiper : init,
      method1 : method1,
      method2 : method2,
    };
    

    问题2: 您需要在init函数内设置变量。在it之外 变量不会引用TkpSlider。

        // init();
        function init() {
            self=this;
            var targetElements = document.getElementsByClassName(this.getItemClass());
            addMultipleListeners(targetElements, 'mousedown touchstart', swipeStart);
            addMultipleListeners(targetElements, 'mousemove touchmove', swipeMove);
            addMultipleListeners(targetElements, 'mouseup touchend', swipeEnd);
            return this;
        }
    

    问题3 您需要手动调用 initSwiper() 方法在创建TkpSlider对象时初始化变量。

    var mainSwiper = new TkpSlider().initSwiper();
    

    然后它将根据需要工作,如果需要,可以调用公共方法。

    mainSwiper.method1();
    mainSwiper.method2();
    

    工作代码段:

    var TkpSlider = function(args) {
      args = args || {};
      //private variable
      var btnPrev = args.btnPrev || "tkp-slide-btn-prev"; //class for previous button (default: "tkp-slide-btn-prev")
      var btnNext = args.btnNext || "tkp-slide-btn-next"; //class for next button (default: "tkp-slide-btn-next")
      var itemClass = args.itemClass || "tkp-slide-item"; //each item container class to slide (default: "tkp-slide-item")
      var isAutoSlide = args.isAutoSlide || false; //set auto slide (default: false)
      var autoSlideTimer = args.autoSlideTimer || 2000; //set auto slide timer when isAutoSlide is true(default: 2000)
      var hideBtnNav = args.hideBtnNav || false; //hide button navigation(default: false)
      var isRandom = args.isRandom || false; //whether next or previous slide should be random index
      var slideIndex = args.startIndex || 0; //start slide index number (zero based, index 0 = slide number 1, default :0)
    
    
      var itemNodes = document.getElementsByClassName(itemClass);
      var itemLength = itemNodes.length;
      var autoSlideInterval;
    
      //public variable
      this.testParentVar = "parent var";
    
      //init function
      init();
    
      function init() {
        if (itemLength > 0) {
          showSlide();
          bindEvent();
          isAutoSlide ? setAutoSlide() : "";
          hideBtnNav ? setHideBtnNav() : "";
        } else {
          throw "Cannot find slider item class";
        }
    
      }
    
    
      //private function
      function showSlide() {
        if (slideIndex >= itemLength) {
          slideIndex = 0;
        }
        if (slideIndex < 0) {
          slideIndex = (itemLength - 1);
        }
        for (var i = 0; i < itemLength; i++) {
          itemNodes[i].style.display = "none";
        }
        itemNodes[slideIndex].style.display = "block";
      }
    
      function nextPrevSlide(n) {
        slideIndex += n;
        showSlide();
      }
    
      function bindEvent() {
        var btnPrevNode = document.getElementsByClassName(btnPrev);
        if (btnPrevNode.length > 0) {
          btnPrevNode[0].addEventListener("click", function() {
    
            if (isRandom) {
              setRandomSlideIndex();
            } else {
              nextPrevSlide(-1);
            }
    
    
            if (isAutoSlide) {
              clearInterval(autoSlideInterval);
              setAutoSlide();
            }
          });
        } else {
          throw "Cannot find button previous navigation";
        }
    
        var btnNextNode = document.getElementsByClassName(btnNext);
        if (btnNextNode.length > 0) {
          btnNextNode[0].addEventListener("click", function() {
            if (isRandom) {
              setRandomSlideIndex();
            } else {
              nextPrevSlide(1);
            }
            if (isAutoSlide) {
              clearInterval(autoSlideInterval);
              setAutoSlide();
            }
          });
        } else {
          throw "Cannot find button next navigation";
        }
    
      }
    
      function setAutoSlide() {
        autoSlideInterval = setInterval(function() {
          if (isRandom) {
            setRandomSlideIndex();
          } else {
            nextPrevSlide(1);
          }
    
        }, autoSlideTimer);
      }
    
      function setHideBtnNav() {
        document.getElementsByClassName(btnPrev)[0].style.display = "none";
        document.getElementsByClassName(btnNext)[0].style.display = "none";
      }
    
      function setRandomSlideIndex() {
        var randomIndex = Math.floor(Math.random() * itemLength);
        if (randomIndex == slideIndex) {
          setRandomSlideIndex();
        } else {
          slideIndex = randomIndex;
          showSlide();
        }
      }
    
      //public function
      this.nextPrevSlide = function(n) {
        nextPrevSlide(n);
        //console.log("nextPrevSlide");
      };
    
      //getter setter
      this.setItemClass = function(prm) {
        itemClass = prm;
      };
      this.getItemClass = function() {
        return itemClass;
      };
    
    
    };
    
    //Adding touch swiper
    TkpSlider.prototype = function() {
      var self;
      var touchStartCoords = {
          'x': -1,
          'y': -1
        }, // X and Y coordinates on mousedown or touchstart events.
        touchEndCoords = {
          'x': -1,
          'y': -1
        }, // X and Y coordinates on mouseup or touchend events.
        direction = 'undefined', // Swipe direction
        minDistanceXAxis = 30, // Min distance on mousemove or touchmove on the X axis
        maxDistanceYAxis = 30, // Max distance on mousemove or touchmove on the Y axis
        maxAllowedTime = 1000, // Max allowed time between swipeStart and swipeEnd
        startTime = 0, // Time on swipeStart
        elapsedTime = 0, // Elapsed time between swipeStart and swipeEnd
        //targetElement = document.getElementById('el'), // Element to delegate
        targetElements; //this.prototype.getItemClass()
      ;
    
      //    init();
      function initSwiper() {
        self = this;
        var targetElements = document.getElementsByClassName(this.getItemClass());
        addMultipleListeners(targetElements, 'mousedown touchstart', swipeStart);
        addMultipleListeners(targetElements, 'mousemove touchmove', swipeMove);
        addMultipleListeners(targetElements, 'mouseup touchend', swipeEnd);
        return this;
      }
    
      function swipeStart(e) {
        e.preventDefault();
        e = e ? e : window.event;
        e = ('changedTouches' in e) ? e.changedTouches[0] : e;
        touchStartCoords = {
          'x': e.pageX,
          'y': e.pageY
        };
        startTime = new Date().getTime();
        //targetElement.textContent = " ";
      }
    
      function swipeMove(e) {
        e = e ? e : window.event;
        e.preventDefault();
      }
    
      function swipeEnd(e) {
        e.preventDefault();
        e = e ? e : window.event;
        e = ('changedTouches' in e) ? e.changedTouches[0] : e;
        touchEndCoords = {
          'x': e.pageX - touchStartCoords.x,
          'y': e.pageY - touchStartCoords.y
        };
        elapsedTime = new Date().getTime() - startTime;
        if (elapsedTime <= maxAllowedTime) {
          if (Math.abs(touchEndCoords.x) >= minDistanceXAxis && Math.abs(touchEndCoords.y) <= maxDistanceYAxis) {
            direction = (touchEndCoords.x < 0) ? 'left' : 'right';
            switch (direction) {
              case 'left':
                //targetElement.textContent = "Left swipe detected";
                console.log("swipe left");
                self.nextPrevSlide(1);
    
                break;
              case 'right':
                // targetElement.textContent = "Right swipe detected";
                console.log("swipe right");
                self.nextPrevSlide(-1);
    
                break;
            }
          }
        }
      }
    
      function addMultipleListeners(el, s, fn) {
        var evts = s.split(' ');
        var elLength = el.length;
        for (var i = 0, iLen = evts.length; i < iLen; i++) {
          if (elLength > 1) {
            for (var j = 0; j < elLength; j++) {
              el[j].addEventListener(evts[i], fn, false);
            }
          } else {
            el.addEventListener(evts[i], fn, false);
          }
    
        }
      }
      return {
        initSwiper: initSwiper
      };
    }();
    
    var mainSwiper = new TkpSlider().initSwiper();
    .tkp-slide {
      width: 100%;
      position: relative;
    }
    
    .tkp-slide .tkp-slide-item:not(:first-child) {
      display: none;
    }
    
    .tkp-slide .tkp-slide-item img {
      width: 100%;
    }
    
    .tkp-slide .tkp-slide-btn {
      color: #fff !important;
      background-color: #000 !important;
      border: none;
      display: inline-block;
      outline: 0;
      padding: 8px 16px;
      vertical-align: middle;
      overflow: hidden;
      text-decoration: none;
      text-align: center;
      cursor: pointer;
      white-space: nowrap;
      opacity: 0.7;
    }
    
    .tkp-slide .tkp-slide-btn:hover {
      background-color: #333 !important;
    }
    
    .tkp-slide .tkp-slide-btn-prev {
      position: absolute;
      top: 50%;
      left: 0%;
      transform: translate(0%, -50%);
      -webkit-transform: translate(0%, -50%);
      -ms-transform: translate(0%, -50%);
    }
    
    .tkp-slide .tkp-slide-btn-next {
      position: absolute;
      top: 50%;
      right: 0%;
      transform: translate(0%, -50%);
      -ms-transform: translate(0%, -50%);
    }
    <section class="main-slide">
      <div class="tkp-slide tkp-slide--container">
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=1" alt="Slide 1" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=2" alt="Slide 2" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=3" alt="Slide 3" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=4" alt="Slide 4" />
          </a>
        </div>
        <div class="tkp-slide-item">
          <a href="javascript:void(0)">
            <img src="https://dummyimage.com/400x200/f2d9f2/080708&text=5" alt="Slide 5" />
          </a>
        </div>
        <ul>
          <li class="tkp-slide-btn tkp-slide-btn-prev">
            &#10094;
          </li>
          <li class="tkp-slide-btn tkp-slide-btn-next">
            &#10095;
          </li>
        </ul>
      </div>
    </section>

    原型混淆:哪个 ?

    TkpSlider.prototype = function() {
    
      console.log(this); /* this this is Child */
      init();
    
      function init() {
        console.log(this); /* this this is Child, called from child context */
      }
    
      function initSwiper() {
        console.log(this); /* this this is Parent, called from parent context */
      }
    
      function swipeStartEventHandler(event) {
        console.log(this); /* this this is HTML element #customId*/
      }
    
      return {
        initSwiper: initSwiper,
      };
    }();
    
    new TkpSlider().initSwiper();