欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

AngularJS自定義插件實(shí)現(xiàn)網(wǎng)站用戶引導(dǎo)功能示例

 更新時(shí)間:2016年11月07日 09:02:45   作者:破狼  
這篇文章主要介紹了AngularJS自定義插件實(shí)現(xiàn)網(wǎng)站用戶引導(dǎo)功能,結(jié)合實(shí)例形式分析了AngularJS自定義插件的實(shí)現(xiàn)步驟與相關(guān)功能技巧,需要的朋友可以參考下

本文實(shí)例講述了AngularJS自定義插件實(shí)現(xiàn)網(wǎng)站用戶引導(dǎo)功能。分享給大家供大家參考,具體如下:

最近由于項(xiàng)目進(jìn)行了較大的改版,為了讓用戶能夠適應(yīng)這次新的改版,因此在系統(tǒng)中引入了“用戶引導(dǎo)”功能,對(duì)于初次進(jìn)入系統(tǒng)的用戶一些簡(jiǎn)單的使用培訓(xùn)training。對(duì)于大多數(shù)網(wǎng)站來說,這是一個(gè)很常見的功能。所以在開發(fā)這個(gè)任務(wù)之前,博主嘗試將其抽象化,獨(dú)立于現(xiàn)有系統(tǒng)的業(yè)務(wù)邏輯,將其封裝為一個(gè)通用的插件,使得代碼更容易擴(kuò)展和維護(hù)。

無圖無真相,先上圖:

關(guān)于這款trainning插件的使用很簡(jiǎn)單,它采用了類似Angular路由一樣的配置,只需要簡(jiǎn)單的配置其每一步training信息。

title:step的標(biāo)題信息;
template/templateUrl: step的內(nèi)容模板信息。這類可以配置html元素,或者是模板的url地址,同時(shí)templateUrl也支持Angular route一樣的function語法;
controller: step的控制器配置;在controller中可注入如下參數(shù):當(dāng)前step – currentStep、所有step的配置 – trainnings、當(dāng)前step的配置 – currentTrainning、以及下一步的操作回調(diào) – trainningInstance(其中nextStep:為下一步的回調(diào),cancel為取消用戶引導(dǎo)回調(diào));
controllerAs: controller的別名;
resolve:在controller初始化前的數(shù)據(jù)配置,同Angular路由中的resolve;
locals:本地變量,和resolve相似,可以傳遞到controller中。區(qū)別之處在于它不支持function調(diào)用,對(duì)于常量書寫會(huì)比resolve更方便;
placement: step容器上三角箭頭的顯示方位,
position: step容器的具體顯示位置,這是一個(gè)絕對(duì)坐標(biāo);可以傳遞{left: 100, top: 100}的絕對(duì)坐標(biāo),也可以是#stepPanelHost配置相對(duì)于此元素的placement位置。同時(shí)它也支持自定義function和注入Angular的其他組件語法。并且默認(rèn)可注入:所有step配置 – trainnings,當(dāng)前步驟 – step,當(dāng)前step的配置 – currentTrainning,以及step容器節(jié)點(diǎn) – stepPanel;
backdrop:是否需要顯示遮罩層,默認(rèn)顯示,除非顯示聲明為false配置,則不會(huì)顯示遮罩層;
stepClass:每一個(gè)step容器的樣式信息;
backdropClass: 每一個(gè)遮罩層的樣式信息。

了解了這些配置后,并根據(jù)特定需求定制化整個(gè)用戶引導(dǎo)的配置信息后,我們就可以使用trainningService的trainning方法來在特定實(shí)際啟動(dòng)用戶引導(dǎo),傳入?yún)?shù)為每一步step的配置信息。并可以注冊(cè)其done或者cancel事件:

trainningService.trainning(trainningCourses.courses)
.done(function() {
 vm.isDone = true;
});

下面是一個(gè)演示的配置信息:

.constant('trainningCourses', {
  courses: [{
   title: 'Step 1:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'left',
   position: '#blogControl'
  },{
   title: 'Step 3:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'top',
   position: {
    top: 200,
    left: 100
   }
  },
   ...
  {
   stepClass: 'last-step',
   backdropClass: 'last-backdrop',
   templateUrl: 'trainning-content-done.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   position: ['$window', 'stepPanel', function($window, stepPanel) {
    // 自定義函數(shù),使其屏幕居中
    var win = angular.element($window);
    return {
     top: (win.height() - stepPanel.height()) / 2,
     left: (win.width() - stepPanel.width()) / 2
    }
   }]
  }]
})

本文插件源碼和演示效果唯一codepen上,效果圖如下:

在trainning插件的源碼設(shè)計(jì)中,包含如下幾個(gè)要點(diǎn):

提供service api。因?yàn)殛P(guān)于trainning這個(gè)插件,它是一個(gè)全局的插件,正好在Angular中所有的service也是單例的,所以將用戶引導(dǎo)邏輯封裝到Angular的service中是一個(gè)不錯(cuò)的設(shè)計(jì)。但對(duì)于trainning的每一步展示內(nèi)容信息則是DOM操作,在Angular的處理中它不該存在于service中,最佳的方式是應(yīng)該把他封裝到Directive中。所以這里采用Directive的定義,并在service中compile,然后append到body中。

對(duì)于每一個(gè)這類獨(dú)立的插件應(yīng)該封裝一個(gè)獨(dú)立的scope,這樣便于在后續(xù)的銷毀,以及不會(huì)與現(xiàn)有的scope變量的沖突。

$q對(duì)延時(shí)觸發(fā)的結(jié)果包裝。對(duì)于像該trainning插件或者modal這類操作結(jié)果采用promise的封裝,是一個(gè)不錯(cuò)的選擇。它取代了回調(diào)參數(shù)的復(fù)雜性,并以流暢API的方式展現(xiàn),更利于代碼的可讀性。同時(shí)也能與其他Angular service統(tǒng)一返回API。

對(duì)于controller、controllerAs、resolve、template、templateUrl這類類似路由的處理代碼,完全可以移到到你的同類插件中去。它們可以增加插件的更多定制化擴(kuò)展。關(guān)于這部分代碼的解釋,博主將會(huì)在后續(xù)文章中為大家推送。

利用$injector.invoke動(dòng)態(tài)注入和調(diào)用Angular service,這樣既能獲取Angular其他service注入的擴(kuò)展性,也能獲取到函數(shù)的動(dòng)態(tài)性。如上例中的屏幕居中的自定義擴(kuò)展方式。

這類設(shè)計(jì)要點(diǎn),同樣可以運(yùn)用到想modal、alert、overload這類全局插件中。有興趣的讀者,你可以在博主的codepen筆記中閱讀這段代碼http://codepen.io/greengerong/pen/pjwXQW#0。

上述代碼摘錄如下:

HTML:

<div ng-app="com.github.greengerong" ng-controller="DemoController as demo">
 <div class="alert alert-success fade in" ng-if='demo.isDone'>
  <strong>All trainning setps done!</strong>
 </div>
 <button id="startAgain" class="btn btn-primary start-again" ng-click="demo.trainning()">You can start trainning again</button>
 <div class="blog">
  <form class="form-inline">
   <div class="form-group">
    <label class="sr-only" for="exampleInputAmount">Blog :</label>
    <div class="input-group">
     <input id="blogControl" type="text" class="form-control" />
    </div>
   </div>
   <button id="submitBlog" class="btn btn-primary" ng-click="demo.backdrop()">Public blog</button>
  </form>
 </div>
 <script type="text/ng-template" id="modal-backdrop.html">
  <div class="modal-backdrop fade in {{backdropClass}}" ng-style="{'z-index': zIndex || 1040}"></div>
 </script>
 <script type="text/ng-template" id="trainning-step.html">
  <div class="trainning-step">
   <div style="display:block; z-index:1080;left:-1000px;top:-1000px;" ng-style="positionStyle" class="step-panel {{currentTrainning.placement}} fade popover in {{currentTrainning.stepClass}}" ng-show="!isProgressing">
    <div class="arrow"></div>
    <div class="popover-inner">
     <h3 class="popover-title" ng-if='currentTrainning.title'>{{currentTrainning.title}}</h3>
     <div class="popover-content">
     </div>
    </div>
   </div>
   <ui-backdrop backdrop-class="currentTrainning.backdropClass" ng-if="currentTrainning.backdrop !== false"></ui-backdrop>
  </div>
 </script>
 <script type="text/ng-template" id="trainning-content.html">
  <div class="step-content">
   <div>{{ stepPanel.texts[stepPanel.currentStep - 1]}}</div>
   <div class="next-step">
    <ul class="step-progressing">
    <li data-ng-repeat="item in stepPanel.trainnings.length | range"
     data-ng-class="{active: stepPanel.currentStep == item}">
    </li>
   </ul>
    <button type="button" class="btn btn-link btn-next pull-right" ng-click="stepPanel.trainningInstance.nextStep({$event:$event, step:step});">Next</button>
   </div>
  </div>
 </script>
 <script type="text/ng-template" id="trainning-content-done.html">
  <div class="step-content">
    <div>
 {{ stepPanel.texts[stepPanel.currentStep - 1]}}
   </div>
   <div class="next-step">
    <ul class="step-progressing">
    <li data-ng-repeat="item in stepPanel.trainnings.length | range"
     data-ng-class="{active: stepPanel.currentStep == item}">
    </li>
   </ul>
    <button type="button" class="btn btn-link pull-right" ng-click="nextStep({$event:$event, step:step});">Got it</button>
   </div>
  </div>
 </script>
</div>

CSS:

.last-step{
 /* background-color: blue;*/
}
.last-backdrop{
 background-color: #FFFFFF;
}
.blog{
 position: absolute;
 left: 300px;
 top: 100px;
}
.start-again{
 position: absolute;
 left: 400px;
 top: 250px;
}
.next-step {
 .step-progressing {
  margin: 10px 0px;
  display: inline-block;
  li {
  margin-right: 5px;
  border: 1px solid #fff;
  background-color: #6E6E6E;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  &.active {
   background-color: #0000FF;
  }
  }
 }
}

JS:

//Please set step content to fixed width when complex content or dynamic loading.
angular.module('com.github.greengerong.backdrop', [])
 .directive('uiBackdrop', ['$document', function($document) {
  return {
   restrict: 'EA',
   replace: true,
   templateUrl: 'modal-backdrop.html',
   scope: {
    backdropClass: '=',
    zIndex: '='
   }
   /* ,link: function(){
    $document.bind('keydown', function(evt){
     evt.preventDefault();
     evt.stopPropagation();
    });
    scope.$on('$destroy', function(){
     $document.unbind('keydown');
    });
    }*/
  };
 }])
 .service('modalBackdropService', ['$rootScope', '$compile', '$document', function($rootScope, $compile, $document) {
  var self = this;
  self.backdrop = function(backdropClass, zIndex) {
   var $backdrop = angular.element('<ui-backdrop></ui-backdrop>')
    .attr({
     'backdrop-class': 'backdropClass',
     'z-index': 'zIndex'
    });
   var backdropScope = $rootScope.$new(true);
   backdropScope.backdropClass = backdropClass;
   backdropScope.zIndex = zIndex;
   $document.find('body').append($compile($backdrop)(backdropScope));
   return function() {
    $backdrop.remove();
    backdropScope.$destroy();
   };
  };
 }]);
angular.module('com.github.greengerong.trainning', ['com.github.greengerong.backdrop', 'ui.bootstrap'])
 .directive('trainningStep', ['$timeout', '$http', '$templateCache', '$compile', '$position', '$injector', '$window', '$q', '$controller', function($timeout, $http, $templateCache, $compile, $position, $injector, $window, $q, $controller) {
  return {
   restrict: 'EA',
   replace: true,
   templateUrl: 'trainning-step.html',
   scope: {
    step: '=',
    trainnings: '=',
    nextStep: '&',
    cancel: '&'
   },
   link: function(stepPanelScope, elm) {
    var stepPanel = elm.find('.step-panel');
    stepPanelScope.$watch('step', function(step) {
     if (!step) {
      return;
     }
     stepPanelScope.currentTrainning = stepPanelScope.trainnings[stepPanelScope.step - 1];
     var contentScope = stepPanelScope.$new(false);
     loadStepContent(contentScope, {
      'currentStep': stepPanelScope.step,
      'trainnings': stepPanelScope.trainnings,
      'currentTrainning': stepPanelScope.currentTrainning,
      'trainningInstance': {
       'nextStep': stepPanelScope.nextStep,
       'cancel': stepPanelScope.cancel
      }
     }).then(function(tplAndVars) {
      elm.find('.popover-content').html($compile(tplAndVars[0])(contentScope));
     }).then(function() {
      var pos = stepPanelScope.currentTrainning.position;
      adjustPosition(stepPanelScope, stepPanel, pos);
     });
    });
    angular.element($window).bind('resize', function() {
     adjustPosition(stepPanelScope, stepPanel, stepPanelScope.currentTrainning.position);
    });
    stepPanelScope.$on('$destroy', function() {
     angular.element($window).unbind('resize');
    });
    function getPositionOnElement(stepScope, setpPos) {
     return $position.positionElements(angular.element(setpPos), stepPanel, stepScope.currentTrainning.placement, true);
    }
    function positionOnElement(stepScope, setpPos) {
     var targetPos = angular.isString(setpPos) ? getPositionOnElement(stepScope, setpPos) : setpPos;
     var positionStyle = stepScope.currentTrainning || {};
     positionStyle.top = targetPos.top + 'px';
     positionStyle.left = targetPos.left + 'px';
     stepScope.positionStyle = positionStyle;
    }
    function adjustPosition(stepScope, stepPanel, pos) {
     if (!pos) {
      return;
     }
     var setpPos = angular.isFunction(pos) || angular.isArray(pos) ? $injector.invoke(pos, null, {
      trainnings: stepScope.trainnings,
      step: stepScope.setp,
      currentTrainning: stepScope.currentTrainning,
      stepPanel: stepPanel
     }) : pos;
     //get postion should wait for content setup
     $timeout(function() {
      positionOnElement(stepScope, setpPos);
     });
    }
    function loadStepContent(contentScope, ctrlLocals) {
     var trainningOptions = contentScope.currentTrainning,
      getTemplatePromise = function(options) {
       return options.template ? $q.when(options.template) :
        $http.get(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl, {
         cache: $templateCache
        }).then(function(result) {
         return result.data;
        });
      },
      getResolvePromises = function(resolves) {
       var promisesArr = [];
       angular.forEach(resolves, function(value) {
        if (angular.isFunction(value) || angular.isArray(value)) {
         promisesArr.push($q.when($injector.invoke(value)));
        }
       });
       return promisesArr;
      },
      controllerLoader = function(trainningOptions, trainningScope, ctrlLocals, tplAndVars) {
       var ctrlInstance;
       ctrlLocals = angular.extend({}, ctrlLocals || {}, trainningOptions.locals || {});
       var resolveIter = 1;
       if (trainningOptions.controller) {
        ctrlLocals.$scope = trainningScope;
        angular.forEach(trainningOptions.resolve, function(value, key) {
         ctrlLocals[key] = tplAndVars[resolveIter++];
        });
        ctrlInstance = $controller(trainningOptions.controller, ctrlLocals);
        if (trainningOptions.controllerAs) {
         trainningScope[trainningOptions.controllerAs] = ctrlInstance;
        }
       }
       return trainningScope;
      };
     var templateAndResolvePromise = $q.all([getTemplatePromise(trainningOptions)].concat(getResolvePromises(trainningOptions.resolve || {})));
     return templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
      controllerLoader(trainningOptions, contentScope, ctrlLocals, tplAndVars);
      return tplAndVars;
     });
    }
   }
  };
 }])
 .service('trainningService', ['$compile', '$rootScope', '$document', '$q', function($compile, $rootScope, $document, $q) {
  var self = this;
  self.trainning = function(trainnings) {
   var trainningScope = $rootScope.$new(true),
    defer = $q.defer(),
    $stepElm = angular.element('<trainning-step></trainning-step>')
    .attr({
     'step': 'step',
     'trainnings': 'trainnings',
     'next-step': 'nextStep($event, step);',
     'cancel': 'cancel($event, step)'
    }),
    destroyTrainningPanel = function(){
     if (trainningScope) {
      $stepElm.remove();
      trainningScope.$destroy();
     }
    };
   trainningScope.cancel = function($event, step){
    defer.reject('cancel');
   };
   trainningScope.nextStep = function($event, step) {
    if (trainningScope.step === trainnings.length) {
     destroyTrainningPanel();
     return defer.resolve('done');
    }
    trainningScope.step++;
   };
   trainningScope.trainnings = trainnings;
   trainningScope.step = 1;
   $document.find('body').append($compile($stepElm)(trainningScope));
   trainningScope.$on('$locationChangeStart', destroyTrainningPanel);
   return {
    done: function(func) {
     defer.promise.then(func);
     return this;
    },
    cancel: function(func) {
     defer.promise.then(null, func);
     return this;
    }
   };
  };
 }]);
angular.module('com.github.greengerong', ['com.github.greengerong.trainning'])
.filter('range', [function () {
   return function (len) {
    return _.range(1, len + 1);
 };
 }])
 .controller('StepPanelController', ['currentStep', 'trainnings', 'trainningInstance', 'trainnings', function(currentStep, trainnings, trainningInstance, trainnings) {
  var vm = this;
  vm.currentStep = currentStep;
  vm.trainningInstance = trainningInstance;
  vm.trainnings = trainnings;
  vm.texts = ['Write your own sort blog.', 'Click button to public your blog.', 'View your blog info on there.', 'Click this button, you can restart this trainning when .', 'All trainnings done!'];
  return vm;
 }])
 .constant('trainningCourses', {
  courses: [{
   title: 'Step 1:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'left',
   position: '#blogControl'
  }, {
   title: 'Step 2:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'right',
   backdrop: false,
   position: '#submitBlog'
  }, {
   title: 'Step 3:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'top',
   position: {
    top: 200,
    left: 100
   }
  }, {
   title: 'Step 4:',
   templateUrl: 'trainning-content.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   placement: 'bottom',
   position: '#startAgain'
  }, {
   stepClass: 'last-step',
   backdropClass: 'last-backdrop',
   templateUrl: 'trainning-content-done.html',
   controller: 'StepPanelController',
   controllerAs: 'stepPanel',
   position: ['$window', 'stepPanel', function($window, stepPanel) {
    var win = angular.element($window);
    return {
     top: (win.height() - stepPanel.height()) / 2,
     left: (win.width() - stepPanel.width()) / 2
    }
   }]
  }]
 })
 .controller('DemoController', ['trainningService', 'trainningCourses', 'modalBackdropService', function(trainningService, trainningCourses, modalBackdropService) {
  var vm = this;
  vm.trainning = function() {
   //call this service should wait your really document ready event.
   trainningService.trainning(trainningCourses.courses)
    .done(function() {
     vm.isDone = true;
    });
  };
  var backdropInstance = angular.noop;
  vm.backdrop = function() {
   modalBackdropService.backdrop();
  };
  vm.trainning();
  return vm;
 }]);

希望本文所述對(duì)大家AngularJS程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • angularjs 源碼解析之scope

    angularjs 源碼解析之scope

    $scope 的使用貫穿整個(gè) Angular App 應(yīng)用,它與數(shù)據(jù)模型相關(guān)聯(lián),同時(shí)也是表達(dá)式執(zhí)行的上下文.有了 $scope 就在視圖和控制器之間建立了一個(gè)通道,基于作用域視圖在修改數(shù)據(jù)時(shí)會(huì)立刻更新 $scope,同樣的 $scope 發(fā)生改變時(shí)也會(huì)立刻重新渲染視圖.
    2016-08-08
  • Angular ng-repeat遍歷渲染完頁面后執(zhí)行其他操作詳細(xì)介紹

    Angular ng-repeat遍歷渲染完頁面后執(zhí)行其他操作詳細(xì)介紹

    這篇文章主要介紹了Angular ng-repeat遍歷渲染完頁面后執(zhí)行其他操作詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • angularjs實(shí)現(xiàn)上拉加載和下拉刷新數(shù)據(jù)功能

    angularjs實(shí)現(xiàn)上拉加載和下拉刷新數(shù)據(jù)功能

    本篇文章主要介紹了angularjs實(shí)現(xiàn)上拉加載和下拉刷新數(shù)據(jù)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • AngularJs基本特性解析(一)

    AngularJs基本特性解析(一)

    angularjs是javascript的一個(gè)框架,通過script標(biāo)簽添加到網(wǎng)頁中。這篇文章主要介紹了AngularJs基本特性解析(一)的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • angular實(shí)現(xiàn)表單驗(yàn)證及提交功能

    angular實(shí)現(xiàn)表單驗(yàn)證及提交功能

    這篇文章主要為大家詳細(xì)介紹了angular實(shí)現(xiàn)表單驗(yàn)證及提交功能的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • AngularJS實(shí)現(xiàn)單獨(dú)作用域內(nèi)的數(shù)據(jù)操作

    AngularJS實(shí)現(xiàn)單獨(dú)作用域內(nèi)的數(shù)據(jù)操作

    這篇文章給大家介紹了利用AngularJs如何實(shí)現(xiàn)ng-repeat內(nèi)各個(gè)小的子作用域單獨(dú)數(shù)據(jù)綁定。有需要的小伙伴們可以參考借鑒,下面來一起看看吧。
    2016-09-09
  • Angular5集成eventbus的示例代碼

    Angular5集成eventbus的示例代碼

    這篇文章主要介紹了Angular5集成eventbus的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • 3個(gè)可以改善用戶體驗(yàn)的AngularJS指令介紹

    3個(gè)可以改善用戶體驗(yàn)的AngularJS指令介紹

    這篇文章主要介紹了3個(gè)可以改善用戶體驗(yàn)的AngularJS指令,AngularJS是一款具有很高人氣的JavaScript框架,需要的朋友可以參考下
    2015-06-06
  • Angular.js自定義指令學(xué)習(xí)筆記實(shí)例

    Angular.js自定義指令學(xué)習(xí)筆記實(shí)例

    這篇文章主要介紹了Angular.js自定義指令的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • AngularJS入門教程之AngularJS表達(dá)式

    AngularJS入門教程之AngularJS表達(dá)式

    AngularJS應(yīng)用表達(dá)式是純javascript表達(dá)式,并輸出它們被使用的數(shù)據(jù)在那里。本文給大家介紹AngularJS入門教程之AngularJS表達(dá)式,對(duì)angularjs表達(dá)式相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2016-04-04

最新評(píng)論