2016-08-15 60 views
-4

我使用了一個使用這個語句塊來顯示菜單的插件,現在我在角度js中使用它。如何將JavaScript函數轉換爲角度js?

(function(window) { 
 

 
\t 'use strict'; 
 

 
\t var support = { animations : Modernizr.cssanimations }, 
 
\t \t animEndEventNames = { 'WebkitAnimation' : 'webkitAnimationEnd', 'OAnimation' : 'oAnimationEnd', 'msAnimation' : 'MSAnimationEnd', 'animation' : 'animationend' }, 
 
\t \t animEndEventName = animEndEventNames[ Modernizr.prefixed('animation') ], 
 
\t \t onEndAnimation = function(el, callback) { 
 
\t \t \t var onEndCallbackFn = function(ev) { 
 
\t \t \t \t if(support.animations) { 
 
\t \t \t \t \t if(ev.target != this) return; 
 
\t \t \t \t \t this.removeEventListener(animEndEventName, onEndCallbackFn); 
 
\t \t \t \t } 
 
\t \t \t \t if(callback && typeof callback === 'function') { callback.call(); } 
 
\t \t \t }; 
 
\t \t \t if(support.animations) { 
 
\t \t \t \t el.addEventListener(animEndEventName, onEndCallbackFn); 
 
\t \t \t } 
 
\t \t \t else { 
 
\t \t \t \t onEndCallbackFn(); 
 
\t \t \t } 
 
\t \t }; 
 

 
\t function extend(a, b) { 
 
\t \t for(var key in b) { 
 
\t \t \t if(b.hasOwnProperty(key)) { 
 
\t \t \t \t a[key] = b[key]; 
 
\t \t \t } 
 
\t \t } 
 
\t \t return a; 
 
\t } 
 

 
\t function MLMenu(el, options) { 
 
\t \t this.el = el; 
 
\t \t this.options = extend({}, this.options); 
 
\t \t extend(this.options, options); 
 
\t \t 
 
\t \t // the menus (<ul>´s) 
 
\t \t this.menus = [].slice.call(this.el.querySelectorAll('.menu__level')); 
 
\t \t // index of current menu 
 
\t \t this.current = 0; 
 

 
\t \t this._init(); 
 
\t } 
 

 
\t MLMenu.prototype.options = { 
 
\t \t // show breadcrumbs 
 
\t \t breadcrumbsCtrl : true, 
 
\t \t // initial breadcrumb text 
 
\t \t initialBreadcrumb : 'all', 
 
\t \t // show back button 
 
\t \t backCtrl : true, 
 
\t \t // delay between each menu item sliding animation 
 
\t \t itemsDelayInterval : 60, 
 
\t \t // direction 
 
\t \t direction : 'r2l', 
 
\t \t // callback: item that doesn´t have a submenu gets clicked 
 
\t \t // onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t onItemClick : function(ev, itemName) { return false; } 
 
\t }; 
 

 
\t MLMenu.prototype._init = function() { 
 
\t \t // iterate the existing menus and create an array of menus, more specifically an array of objects where each one holds the info of each menu element and its menu items 
 
\t \t this.menusArr = []; 
 
\t \t var self = this; 
 
\t \t this.menus.forEach(function(menuEl, pos) { 
 
\t \t \t var menu = {menuEl : menuEl, menuItems : [].slice.call(menuEl.querySelectorAll('.menu__item'))}; 
 
\t \t \t self.menusArr.push(menu); 
 

 
\t \t \t // set current menu class 
 
\t \t \t if(pos === self.current) { 
 
\t \t \t \t classie.add(menuEl, 'menu__level--current'); 
 
\t \t \t } 
 
\t \t }); 
 

 
\t \t // create back button 
 
\t \t if(this.options.backCtrl) { 
 
\t \t \t this.backCtrl = document.createElement('button'); 
 
\t \t \t this.backCtrl.className = 'menu__back menu__back--hidden'; 
 
\t \t \t this.backCtrl.setAttribute('aria-label', 'Go back'); 
 
\t \t \t this.backCtrl.innerHTML = '<span class="icon icon--arrow-left"></span>'; 
 
\t \t \t this.el.insertBefore(this.backCtrl, this.el.firstChild); 
 
\t \t } 
 
\t \t 
 
\t \t 
 
\t \t // create breadcrumbs 
 
\t \t if(self.options.breadcrumbsCtrl) { 
 
\t \t \t this.breadcrumbsCtrl = document.createElement('nav'); 
 
\t \t \t this.breadcrumbsCtrl.className = 'menu__breadcrumbs'; 
 
\t \t \t this.el.insertBefore(this.breadcrumbsCtrl, this.el.firstChild); 
 
\t \t \t // add initial breadcrumb 
 
\t \t \t this._addBreadcrumb(0); 
 
\t \t } 
 

 
\t \t // event binding 
 
\t \t this._initEvents(); 
 
\t }; 
 

 
\t MLMenu.prototype._initEvents = function() { 
 
\t \t var self = this; 
 

 
\t \t for(var i = 0, len = this.menusArr.length; i < len; ++i) { 
 
\t \t \t this.menusArr[i].menuItems.forEach(function(item, pos) { 
 
\t \t \t \t item.querySelector('a').addEventListener('click', function(ev) { 
 
\t \t \t \t \t var submenu = ev.target.getAttribute('data-submenu'), 
 
\t \t \t \t \t \t itemName = ev.target.innerHTML, 
 
\t \t \t \t \t \t subMenuEl = self.el.querySelector('ul[data-menu="' + submenu + '"]'); 
 

 
\t \t \t \t \t // check if there's a sub menu for this item 
 
\t \t \t \t \t if(submenu && subMenuEl) { 
 
\t \t \t \t \t \t ev.preventDefault(); 
 
\t \t \t \t \t \t // open it 
 
\t \t \t \t \t \t self._openSubMenu(subMenuEl, pos, itemName); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else { 
 
\t \t \t \t \t \t // add class current 
 
\t \t \t \t \t \t var currentlink = self.el.querySelector('.menu__link--current'); 
 
\t \t \t \t \t \t if(currentlink) { 
 
\t \t \t \t \t \t \t classie.remove(self.el.querySelector('.menu__link--current'), 'menu__link--current'); 
 
\t \t \t \t \t \t } 
 
\t \t \t \t \t \t classie.add(ev.target, 'menu__link--current'); 
 
\t \t \t \t \t \t 
 
\t \t \t \t \t \t // callback 
 
\t \t \t \t \t \t self.options.onItemClick(ev, itemName); 
 
\t \t \t \t \t } 
 
\t \t \t \t }); 
 
\t \t \t }); 
 
\t \t } 
 
\t \t 
 
\t \t // back navigation 
 
\t \t if(this.options.backCtrl) { 
 
\t \t \t this.backCtrl.addEventListener('click', function() { 
 
\t \t \t \t self._back(); 
 
\t \t \t }); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._openSubMenu = function(subMenuEl, clickPosition, subMenuName) { 
 
\t \t if(this.isAnimating) { 
 
\t \t \t return false; 
 
\t \t } 
 
\t \t this.isAnimating = true; 
 
\t \t 
 
\t \t // save "parent" menu index for back navigation 
 
\t \t this.menusArr[this.menus.indexOf(subMenuEl)].backIdx = this.current; 
 
\t \t // save "parent" menu´s name 
 
\t \t this.menusArr[this.menus.indexOf(subMenuEl)].name = subMenuName; 
 
\t \t // current menu slides out 
 
\t \t this._menuOut(clickPosition); 
 
\t \t // next menu (submenu) slides in 
 
\t \t this._menuIn(subMenuEl, clickPosition); 
 
\t }; 
 

 
\t MLMenu.prototype._back = function() { 
 
\t \t if(this.isAnimating) { 
 
\t \t \t return false; 
 
\t \t } 
 
\t \t this.isAnimating = true; 
 

 
\t \t // current menu slides out 
 
\t \t this._menuOut(); 
 
\t \t // next menu (previous menu) slides in 
 
\t \t var backMenu = this.menusArr[this.menusArr[this.current].backIdx].menuEl; 
 
\t \t this._menuIn(backMenu); 
 

 
\t \t // remove last breadcrumb 
 
\t \t if(this.options.breadcrumbsCtrl) { 
 
\t \t \t this.breadcrumbsCtrl.removeChild(this.breadcrumbsCtrl.lastElementChild); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._menuOut = function(clickPosition) { 
 
\t \t // the current menu 
 
\t \t var self = this, 
 
\t \t \t currentMenu = this.menusArr[this.current].menuEl, 
 
\t \t \t isBackNavigation = typeof clickPosition == 'undefined' ? true : false; 
 

 
\t \t // slide out current menu items - first, set the delays for the items 
 
\t \t this.menusArr[this.current].menuItems.forEach(function(item, pos) { 
 
\t \t \t item.style.WebkitAnimationDelay = item.style.animationDelay = isBackNavigation ? parseInt(pos * self.options.itemsDelayInterval) + 'ms' : parseInt(Math.abs(clickPosition - pos) * self.options.itemsDelayInterval) + 'ms'; 
 
\t \t }); 
 
\t \t // animation class 
 
\t \t if(this.options.direction === 'r2l') { 
 
\t \t \t classie.add(currentMenu, !isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t } 
 
\t \t else { 
 
\t \t \t classie.add(currentMenu, isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); \t 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._menuIn = function(nextMenuEl, clickPosition) { 
 
\t \t var self = this, 
 
\t \t \t // the current menu 
 
\t \t \t currentMenu = this.menusArr[this.current].menuEl, 
 
\t \t \t isBackNavigation = typeof clickPosition == 'undefined' ? true : false, 
 
\t \t \t // index of the nextMenuEl 
 
\t \t \t nextMenuIdx = this.menus.indexOf(nextMenuEl), 
 

 
\t \t \t nextMenuItems = this.menusArr[nextMenuIdx].menuItems, 
 
\t \t \t nextMenuItemsTotal = nextMenuItems.length; 
 

 
\t \t // slide in next menu items - first, set the delays for the items 
 
\t \t nextMenuItems.forEach(function(item, pos) { 
 
\t \t \t item.style.WebkitAnimationDelay = item.style.animationDelay = isBackNavigation ? parseInt(pos * self.options.itemsDelayInterval) + 'ms' : parseInt(Math.abs(clickPosition - pos) * self.options.itemsDelayInterval) + 'ms'; 
 

 
\t \t \t // we need to reset the classes once the last item animates in 
 
\t \t \t // the "last item" is the farthest from the clicked item 
 
\t \t \t // let's calculate the index of the farthest item 
 
\t \t \t var farthestIdx = clickPosition <= nextMenuItemsTotal/2 || isBackNavigation ? nextMenuItemsTotal - 1 : 0; 
 

 
\t \t \t if(pos === farthestIdx) { 
 
\t \t \t \t onEndAnimation(item, function() { 
 
\t \t \t \t \t // reset classes 
 
\t \t \t \t \t if(self.options.direction === 'r2l') { 
 
\t \t \t \t \t \t classie.remove(currentMenu, !isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t \t \t \t \t classie.remove(nextMenuEl, !isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else { 
 
\t \t \t \t \t \t classie.remove(currentMenu, isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t \t \t \t \t classie.remove(nextMenuEl, isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t classie.remove(currentMenu, 'menu__level--current'); 
 
\t \t \t \t \t classie.add(nextMenuEl, 'menu__level--current'); 
 

 
\t \t \t \t \t //reset current 
 
\t \t \t \t \t self.current = nextMenuIdx; 
 

 
\t \t \t \t \t // control back button and breadcrumbs navigation elements 
 
\t \t \t \t \t if(!isBackNavigation) { 
 
\t \t \t \t \t \t // show back button 
 
\t \t \t \t \t \t if(self.options.backCtrl) { 
 
\t \t \t \t \t \t \t classie.remove(self.backCtrl, 'menu__back--hidden'); 
 
\t \t \t \t \t \t } 
 
\t \t \t \t \t \t 
 
\t \t \t \t \t \t // add breadcrumb 
 
\t \t \t \t \t \t self._addBreadcrumb(nextMenuIdx); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else if(self.current === 0 && self.options.backCtrl) { 
 
\t \t \t \t \t \t // hide back button 
 
\t \t \t \t \t \t classie.add(self.backCtrl, 'menu__back--hidden'); 
 
\t \t \t \t \t } 
 

 
\t \t \t \t \t // we can navigate again.. 
 
\t \t \t \t \t self.isAnimating = false; 
 
\t \t \t \t }); 
 
\t \t \t } 
 
\t \t }); \t 
 
\t \t 
 
\t \t // animation class 
 
\t \t if(this.options.direction === 'r2l') { 
 
\t \t \t classie.add(nextMenuEl, !isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t } 
 
\t \t else { 
 
\t \t \t classie.add(nextMenuEl, isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._addBreadcrumb = function(idx) { 
 
\t \t if(!this.options.breadcrumbsCtrl) { 
 
\t \t \t return false; 
 
\t \t } 
 

 
\t \t var bc = document.createElement('a'); 
 
\t \t bc.innerHTML = idx ? this.menusArr[idx].name : this.options.initialBreadcrumb; 
 
\t \t this.breadcrumbsCtrl.appendChild(bc); 
 

 
\t \t var self = this; 
 
\t \t bc.addEventListener('click', function(ev) { 
 
\t \t \t ev.preventDefault(); 
 

 
\t \t \t // do nothing if this breadcrumb is the last one in the list of breadcrumbs 
 
\t \t \t if(!bc.nextSibling || self.isAnimating) { 
 
\t \t \t \t return false; 
 
\t \t \t } 
 
\t \t \t self.isAnimating = true; 
 
\t \t \t 
 
\t \t \t // current menu slides out 
 
\t \t \t self._menuOut(); 
 
\t \t \t // next menu slides in 
 
\t \t \t var nextMenu = self.menusArr[idx].menuEl; 
 
\t \t \t self._menuIn(nextMenu); 
 

 
\t \t \t // remove breadcrumbs that are ahead 
 
\t \t \t var siblingNode; 
 
\t \t \t while (siblingNode = bc.nextSibling) { 
 
\t \t \t \t self.breadcrumbsCtrl.removeChild(siblingNode); 
 
\t \t \t } 
 
\t \t }); 
 
\t }; 
 

 
\t window.MLMenu = MLMenu; 
 

 
})(window);

和定製的Java腳本:

(function() { 
 
\t  var menuEl = document.getElementById('ml-menu'); 
 
\t \t \t mlmenu = new MLMenu(menuEl, { 
 
\t \t \t \t // breadcrumbsCtrl : true, // show breadcrumbs 
 
\t \t \t \t // initialBreadcrumb : 'all', // initial breadcrumb text 
 
\t \t \t \t backCtrl : false, // show back button 
 
\t \t \t \t // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
\t \t \t \t onItemClick: loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t \t }); 
 

 
\t \t //mobile menu toggle 
 
\t \t var openMenuCtrl = document.querySelector('.action--open'), 
 
\t \t \t closeMenuCtrl = document.querySelector('.action--close'); 
 

 
\t \t openMenuCtrl.addEventListener('click', openMenu); 
 
\t \t closeMenuCtrl.addEventListener('click', closeMenu); 
 

 
\t \t function openMenu() { 
 
\t \t \t classie.add(menuEl, 'menu--open'); 
 
\t \t } 
 

 
\t \t function closeMenu() { 
 
\t \t \t classie.remove(menuEl, 'menu--open'); 
 
\t \t } 
 

 
\t \t // simulate grid content loading 
 
\t \t var gridWrapper = document.querySelector('.content'); 
 

 
\t \t function loadDummyData(ev, itemName) { 
 
\t \t \t ev.preventDefault(); 
 

 
\t \t \t closeMenu(); 
 
\t \t \t gridWrapper.innerHTML = ''; 
 
\t \t \t classie.add(gridWrapper, 'content--loading'); 
 
\t \t \t setTimeout(function() { 
 
\t \t \t \t classie.remove(gridWrapper, 'content--loading'); 
 
\t \t \t \t gridWrapper.innerHTML = '<ul class="products">' + dummyData[itemName] + '<ul>'; 
 
\t \t \t }, 700); 
 
\t \t } 
 
\t })();

我想下面這個自定義腳本的一部分轉變爲角JS。

mlmenu = new MLMenu(menuEl, { 
 
\t \t \t \t // breadcrumbsCtrl : true, // show breadcrumbs 
 
\t \t \t \t // initialBreadcrumb : 'all', // initial breadcrumb text 
 
\t \t \t \t backCtrl : false, // show back button 
 
\t \t \t \t // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
\t \t \t \t onItemClick: loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t \t });

我使用它,因爲這在角,但有錯誤。

$scope.menuEl = document.getElementById('ml-menu'); 
 
    var menuEl = document.getElementById('ml-menu'), 
 
    mlmenu = new MLMenu(menuEl, { 
 
       
 
       // breadcrumbsCtrl : true, // show breadcrumbs 
 
       // initialBreadcrumb : 'all', // initial breadcrumb text 
 
       backCtrl: false, // show back button 
 
       // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
       onItemClick: $scope.loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
    });

我該怎麼辦呢?

回答

0

我想你應該AngularJS指令https://docs.angularjs.org/guide/directive

即包你的插件創建使用插件的指令並在標記的DOM上初始化它。

angular.module('yourModule') 
.directive('mlMenu', function() { 
    return { 
    restrict: 'A', 
    link: function (scope, element) { 
     var mlmenu = new MLMenu(element, 
     ... 
    } 
    }; 
}); 

比HTML

<div data-ml-menu></div> 

如果你打算在插件聽衆不要忘記使用scope.$apply()包裝修改範圍。