<!DOCTYPE html> <html ng-app> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>雙向綁定(第一印象)</title> <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script> </head> <body> <input type="text" ng-model="msg"> {{msg}} </body> </html>
Mjavascript
Vphp
數據模型變化驅動視圖視圖html
聲明式 UI 結構vue
Cjava
做用域 $scopereact
做用域層級與繼承jquery
做用域與事件系統angularjs
var myMod = angular.module('myMod', []);
爲何要使用模塊?bootstrap
咱們須要使用其餘的協做模塊怎麼辦?後端
簡單回答開始的兩個問題:
問題一:若是不使用模塊,那隻能使用全局的控制器方式。污染全局變量,難以管理、維護、組織、複用代碼。
模塊化能夠解決這些問題,它帶來了命名空間和組織代碼,複用代碼等。
問題二:依賴注入解決模塊之間的協做問題。
低級版本Angular中使用controller不須要在模塊中註冊
<!DOCTYPE html> <html ng-app> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>低級版本Angular中使用controller不須要模塊</title> <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script> </head> <body> <p>低級版本Angular中使用controller不須要模塊</p> <div ng-controller="HelloCtrl"> <input type="text" ng-model="data.msg"> {{data.msg}} </div> <script type="text/javascript"> var HelloCtrl = function($scope) { $scope.data = {msg:123}; } </script> </body> </html>
以後控制器的須要在模塊上註冊
<!DOCTYPE html> <html ng-app="myMod"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>模塊上註冊控制器</title> <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script> </head> <body> <div ng-controller="helloCtrl"> <input type="text" ng-model="msg"> {{msg}} </div> <script type="text/javascript"> var myMod = angular.module('myMod', []); myMod.controller('helloCtrl', function($scope) { $scope.msg = "msg"; }); </script> </body> </html>
var myMod = angular.module('myMod', []); myMod.controller('helloCtrl', function($scope) { $scope.msg = "msg"; });
值 myMod.value(...)
服務
myMod.service(...)
myMod.factory(...)
myMod.provider(...)
myMode.constant(...)
除了 constant,其餘都是 provider 的封裝。
配置階段:收集對象建立的解決方案,並進行配置。 myMod.config(...)
運行階段:執行全部初始化後的邏輯。myMod.run(...)
不一樣的階段與不一樣的註冊方法。
配置階段能夠注入:常量值、Provider
運行階段能夠注入:常量值、變量值、Service、Factory
var myMod = angular.module('myMod', ['myMod2', 'myMod3']);
服務的跨模塊可見性
兄弟模塊之間能夠相互使用服務,也能夠覆蓋兄弟的服務。
myModule.directive('myDir', function(){ return myDirDefine; });
myDirDefine 是個對象,有幾個基本的屬性:
name 指令名稱
restrict 指令存在形式A(屬性attribute)、E(element)、C(class)、M(comment),常見的是 A 和 E
templte 指令模版字符串
templateUrl 指令模版的URL路徑
replace 是否使用模版內容替換指令現有的元素
tansclude 是否爲指令模版和編譯函數提供指令元素中的內容。vue.js中 稱之爲 slot(插槽)
scope 做用域
controller 指令控制器函數,做用:對外提供接口
require 設置須要注入的指令,也就是須要依賴的指令
link 連接函數:處理指令內部事務,好比 Dom 操做等
compile 編譯函數
在指令上定義屬性與外部的控制器進行交互
例子1:
項目中使用(AngularUI 中翻頁指令的使用):
uib-pagination 翻頁指令和外部控制器的 方法 pageChanged(e) 須要進行交互
<uib-pagination total-items="groups.total" ng-model="currentPage" class="pagination-sm" ng-change="pageChanged(e)"></uib-pagination>
參考:大漠窮秋的學習視頻 《AngularJS實戰》
在指令 loader 上定義屬性 howToLoad,與外部控制器交互
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script> </head> <style> .loader{ background-color: blue; padding-top:5px } </style> <body> <div ng-controller="helloCtrl"> <input type="text" ng-model="msg"> {{msg}} </div> <div ng-controller="helloCtrl1"> <loader howToLoad="loadData1()"></loader> </div> <div> <p>ddd</p> </div> <div ng-controller="helloCtrl2"> <loader howToLoad="loadData2()"></loader> </div> <script type="text/javascript"> var myModule = angular.module('myModule', []); myModule.controller('helloCtrl', function($scope) { $scope.msg = "hahaha"; }); myModule.controller('helloCtrl1', function($scope) { $scope.loadData1 = function(){ console.log('加載數據1'); }; }); myModule.controller('helloCtrl2', function($scope) { $scope.loadData2 = function(){ console.log('加載數據2'); }; }); myModule.directive('loader', function(){ return { restrict:'E', template:'<div class="loader">加載數據指令</div>', link: function(scope, element, attr){ element.bind('mouseenter', function(){ scope.$apply(attr.howtoload); }) } }; }); angular.bootstrap(document, ['myModule']); </script> </body> </html>
指令的controller 爲指令對外暴露一組public方法,提供給其餘指令調用
require 設置依賴的指令
link 函數中第四個參數,將獲得依賴指令的控制器
咱們常常會看到不少指令編寫會依賴 ng-model 指令,例以下面的指令
myMod.directive('phoneNo', function() { return { restrict: 'A', require: '?ngModel', link: function(scope, element, attrs, ngModelCtrl) { if (!ngModelCtrl) return; function validPhoneNo(value) { var PHONE_NO_REGEXP = /^1[3|4|5|8][0-9]\d{8}$/; var valid = !ngModelCtrl.$isEmpty(value) && PHONE_NO_REGEXP.test(value); ngModelCtrl.$setValidity('valid', valid); return valid ? value : undefined; } ngModelCtrl.$parsers.unshift(validPhoneNo); ngModelCtrl.$formatters.unshift(validPhoneNo); } }; });
使用指令:
<input phone-no type="tel" placeholder="填寫11位有效手機號碼" ng-model="address.phoneNo" required>
固然能夠更簡單的使用官方的 ng-pattern 指令
<input type="tel" ng-pattern="/^1[3|4|5|8][0-9]\d{8}$/" placeholder="填寫11位有效手機號碼" ng-model="address.phoneNo" required>
參考:大漠窮秋的學習視頻 《AngularJS實戰》
指令 player 在本身的控制器上定義了對外能夠調用的接口
指令 power、指令 speed、指令 height 分別都定義了須要依賴 指令 player、而且在自身的 link 函數中使用了 player 的接口。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script> </head> <style> .loader{ background-color: blue; padding-top:5px } </style> <body> <div ng-controller="helloCtrl"> <input type="text" ng-model="msg"> {{msg}} <div> <player power>球員1 :力量</player> </div> <div> <player power speed>球員2:力量 + 速度</player> </div> <div> <player power speed height>球員3: 力量 + 速度 + 身高</player> </div> </div> <script type="text/javascript"> var myModule = angular.module('myModule', []); myModule.controller('helloCtrl', function($scope) { $scope.msg = "hahaha"; }); myModule.directive('player', function(){ return { restrict:'AE', scope:{}, controller:function($scope){ $scope.ability = []; this.addPower = function(){ $scope.ability.push('power'); }; this.addSpeed = function(){ $scope.ability.push('speed'); }; this.addHeight = function(){ $scope.ability.push('height'); }; }, link: function(scope, element, attr){ element.bind('mouseenter', function(){ console.log(scope.ability); }) } }; }); myModule.directive('power', function(){ return { restrict:'A', require: '^player', link: function(scope, element, attr, controller){ controller.addPower() }; }; }); myModule.directive('speed', function(){ return { restrict:'A', require: '^player', link: function(scope, element, attr, controller){ controller.addSpeed() }; }; }); myModule.directive('height', function(){ return { restrict:'A', require: '^player', link: function(scope, element, attr, controller){ controller.addHeight() }; }; }); angular.bootstrap(document, ['myModule']); </script> </body> </html>
scope 的取值
false 默認是false,複用組件具體位置所在的做用域
true 建立子做用域,該做用域繼承來自它具體所在位置的做用域
{...} 建立獨立做用域,與父做用域徹底隔離
實際開發中每每咱們會建立獨立做用域,完成與父做用域隔離。
能夠經過監視來是屬性表達式與模版做用域的屬性保持一致,但須要手動設置來實現(在link中顯示的從attr中讀取值,並賦值給scope)。
更方便的是使用scope的綁定策略。
@:使用@將屬性做爲字符串傳遞給指令(例子中的str),也能夠將外層的scope值在屬性值中以{{}}插入(例子中的str2)
=:與外部的屬性進行雙向綁定
&:傳遞外部的一個回調函數
scope:{ attr1:'@attribute1', attr2:'=attribute2', attr3:'&attribute3' }
首先這裏的 scope 是獨立做用域,關於綁定策略須要 注意 兩點:
屬性命名使用 - 鏈接,變量變現爲駝峯式
回調函數傳遞參數的寫法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>指令的scope</title> <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script> </head> <style> .loader{ background-color: blue; padding-top:5px } </style> <body> <div ng-controller="helloCtrl"> <input type="text" ng-model="msg"> <input type="text" ng-model="str2"> <input type="text" ng-model="str"> <p>如下是指令</p> <my-directive msg="msg" str="1234" str2={{str2}} click-btn="clickBtn(name)">自己的html</my-directive> </div> <script type="text/javascript"> var myModule = angular.module('myModule', []); myModule.controller('helloCtrl', function($scope) { $scope.msg = "hahaha"; $scope.str2 = "使用@傳遞一個字符串"; $scope.clickBtn = function(name){ console.log(name); } }); myModule.directive('myDirective', function(){ return { restrict:'E', scope:{ msg:'=', str:'@', str2:'@', clickBtn: '&' }, template:'<input type="text" ng-model="msg"><p>{{str}}</p><p>{{str2}}</p><input type="text" ng-model="userName"><button ng-click="clickBtn({name:userName})">Click Me</button>', link: function(scope, ele, attr){ console.log(scope); console.log(attr); } }; }) angular.bootstrap(document, ['myModule']); </script> </body> </html>
<component-a :msg="msg" hh="來自字面量語法" :click-handle="clickHandle"></component-a>
<my-component :foo="baz" :bar="qux" @event-a="doThis" @event-b="doThat"> <!-- content --> <img slot="icon" src="..."> <p slot="main-text">Hello!</p> </my-component>
組件的 API 來自三部分:props、事件、slot
-props 容許外部環境傳遞數據給組件(其中數據也能夠是 action)
-事件 容許在組件內觸發外部環境的 action
-slot 容許外部環境插入內容到組件的視圖結構內 (包括指定插入內容在組件中的位置)
react 也是經過 props 傳遞。對屬性命名沒有和Angular、vue這種要求
<MiniPost ref="miniPost" onOk={this.sendPost} placeholder={postPlaceholder}/>
Angularjs 適合管理後臺類型的項目
開發效率高
先後端部分解耦
1、使用 requirejs 管理咱們的js文件(不強求),這一步和 angularjs 沒有關係。
require.config({ urlArgs: "v=" + (new Date()).getTime(),// 體驗環境和正式環境會替換爲構建版本號 baseUrl: "/js/", paths: { "jquery": "vendor/jquery-1.11.3.min", "underscore": "vendor/underscore.min", "moment": "vendor/moment.min", "angular": "vendor/angular.min", "ui-router": "vendor/angular-ui-router.min", "ng-file-upload": "vendor/ng-file-upload", "ng-sanitize": "vendor/angular-sanitize.min", "ui-bootstrap": "vendor/ui-bootstrap-tpls-0.12.1.min", "angular-datetimepicker": "vendor/angular-datetimepicker", "ui-select": "vendor/ui-select", "checklist-model": "vendor/checklist-model", "directives": "vendor/directives", "tfl": "tfl/js/tfl-core", "tfl-editor": "tfl/js/tfl-editor" }, shim: { "angular": { exports: "angular" }, "ui-router": { deps: ["angular"] }, "ng-file-upload": { deps: ["angular"] }, "ng-sanitize": { deps: ["angular"] }, "ui-bootstrap": { deps: ["angular"] }, "ui-select": { deps: ["angular"] }, "checklist-model": { deps: ["angular"] }, "angular-datetimepicker": { deps: ["angular", "moment"] }, "serviceModule": { deps: ["angular"] }, "directives": { deps: ["angular", 'tfl'] } } });
2、咱們不會整站在根目錄下直接使用,而是根據不一樣業務模塊分拆開,這樣有利於代碼的維護和組織,我的認爲這點很重要
網站路由 一部分交給後臺(/shop/goods)、一部分交給 angular(#/部分)
http://demo.com/shop/goods#/ http://demo.com/shop/goods#/detail/100034 http://demo.com/shop/goods#/edit/100034 http://demo.com/shop/goods#/edit/100034
demo.com/shop/goods 後臺 php 吐出的直出的頁面(固然這個的外出有個整站的layout)
<div ui-view></div> <script> require(['shop/goods'], function(){ }); </script>
業務 shop/goods.js
define(['jquery', 'angular', 'ui-router', 'serviceModule'], function($, angular) { var myModule = angular.module('myModule', [ 'ui.router', 'serviceModule' ]); myModule.config(['$httpProvider', '$stateProvider', '$urlRouterProvider', function($httpProvider, $stateProvider, $urlRouterProvider) { $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; $httpProvider.defaults.transformRequest = function(data) { if (data === undefined) { return data; } return $.param(data); }; $urlRouterProvider.otherwise('/'); $stateProvider.state('demo', { abstract: true, url: '/', template: '<div ui-view></div>', controller: ['$scope', function($scope) { }] }); $stateProvider.state('demo.list', { url: '', pageTitle: 'list頁', templateUrl: '/views/demo.list.html', controller: ['$scope', function($scope) { }] }); $stateProvider.state('demo.detail', { url: 'detail/{id:[0-9]+}', pageTitle: '詳情頁', templateUrl: '/views/demo.detail.html', resolve: { data: ['$stateParams', 'Test', function($stateParams, Test) { return Test.fetch($stateParams.id); }] }, controller: ['$scope', 'data', function($scope, data) { console.log(12); $scope.data = data; }] }); $stateProvider.state('demo.add', { url: 'add', pageTitle: '新增編輯頁', templateUrl: '/views/demo.add.html', controller: ['$scope', function($scope) { console.log('add'); }] }); }]); angular.bootstrap(document, ['myModule']); });
serviceModule.js 定義一個和後臺數據交換的模塊 serviceModule
define(['angular'], function(angular) { 'use strict'; var serviceModule = angular.module('serviceModule', []); serviceModule.factory('Test', ['$http', function($http) { return { fetch: function(id) { return $http.get('/test/get/' + id).then(function(res) { return res.data; }); }, list: function(search) { return $http.get('/test/list', {params: search}).then(function(res) { return res.data; }); }, save: function(data, cb) { $http.post('/test/save', data).success(cb); } }; }]); });
就這樣商品模塊就搞定啦。