angular.js 示例应用程序

分享于 

49分钟阅读

Web开发

  繁體

演示应用程序代码:是一个链接,你可以在这里下载以下内容: 演示应用程序

目录
  • 简介
  • 演示应用概述。
  • angular.js 简介
  • 发布服务器
  • angular.js 网站
  • ,那是什么
  • 简介

    这篇文章是我第一段时间,有一个原因,但是我不会把你们全部解开。 总之,我在一段时间后写了这篇文章。 那么它是做什么的这篇文章是什么?

    I Google框架,我决定花一点时间学习一个流行的web MVC框架,这对于我来说是一个JavaScript的框架,这对我来说是一个很好的选择,因为我经常会影响到世界。 try尝试如何用不同语言/环境来做事情很好,因此我决定采取 angular.js的方式,所以我决定采用( spin ) 来进行旋转。

    本文将讨论 angular.js 插件的一些基本思想,然后着重讨论我创建的演示应用程序的细节。

    在我们进入实际文章之前,我只是在 breifly ( 现在不太技术了,尽管我知道你们会想看到这个,而且它不会担心。) 谈论演示应用程序。

    演示应用概述。

    有 2个部分的附加演示应用

    发布服务器

    这是一个标准的WPF项目,因此产生一个可以运行的EXE文件。 这篇文章的内容不会太多,因为它不是文章的重要部分,只是在 angular.js 网站中展示内容的一种工具。 publisher发布者在单击图像时,使用网络套接字将消息发送到 angular.js 站点,以允许用户点击图片。 简而言之,出版商所做的就是。

    网站

    angular.js 网站,就是在这里出现了有趣的事情。angular.js 网站基本上执行这些任务

    root 页面将显示每个接收到的消息的图像平铺。 图片平铺可以调整和拖动周围,因为一些 jQuery UI的爱。 用户可以选择将图像平铺保存到他们的收藏,这将导致所有的信息将保存到 HTML 5本地存储的信息。 这些信息包括大小。位置等,所以当用户回到 root 页面时,他们的最爱( 他们保存的那些) 应该像以前一样出现。 用户也可能决定从 root 页面中删除他们的收藏。

    • 用户还可以选择导航到一个收藏页面,该页面将显示它的HTML 5本地存储持久化收藏夹的一些缩略图图像。 这些缩略图可以被点击以显示一个非常标准的ColorBox ( 收藏夹等类型) jQuery插件。
    • 对于一个页面,用户也可以选择查看页面,我只是添加了足够的路径,以便在demonstating中的路由出现问题时使之更值得

    所以,这个图像可以能有助于解固我刚才用单词表达的,图片 1000nd 和所有的内容:

    这就是本文的2部分在正确运行时应该显示的代码:

    Click Click Click Click Click

    重要注意事项:

    确保按照以下步骤成功运行演示代码

  • 你发现,如果你发现一些项目引用无法找到,我将它们包含在一个"lib"文件夹中,你可以从引用它们。
  • 你应该确保 Publisher.Wpf 项目首先运行,并且它显示了所有的图像。 可以通过将 Publisher.Wpf 项目构建到 EXE,并在文件系统中单击EXE以运行( 或者使用 Visual Studio 运行)。
  • 然后运行 Angular 网站,确保将 index.html 设置为 Visual Studio 中的起始页,然后使用 Visual Studio 运行 Angular web站点。
  • angular.js 简介

    在本节中,我将讨论使用 angular.js 插件的一些基础。 本节将是我自己的文字,并直接从 angular.js的网站上提升。 因为我不会把 angular.js的所有内容都覆盖起来,因为这是一本书,我只是没有那么多时间。 不过,我将覆盖一些基本的 angular.js 构建块,因此你应该阅读本文并按照教程的超链接来思考。

    应用程序

    在某种程度上,每个 angular.js 应用程序都需要使用angular.jsng-app 绑定,或者通过与 declaritive html绑定相同的代码执行相同的工作。 这里代码essentialy引导 angular.js,并让它知道应用程序运行的上下文。 例如你可能有以下代码:

    <divid="outer"><divid="inner"ng-app="myApp"><p>{{name}}</p></div><p>This is not using the angular app, as it is not within the Angular apps scope</p></div>

    可以看出,我们可以将html的特定部分作为 angular.js 应用程序的一个应用。 在本例中,这意味着

    id="inner"
    会有一部分 html ( 虽然没有什么可以阻止你做实际的身体标记是 Angular 应用) 被认为是 angular.js 应用程序,这样就可以完全访问angular.js 插件应用程序功能。

    在不需要考虑 id="outer"应用程序的情况下,不可能被认为是 angular.js 应用程序的一部分,因此对angular.js 应用程序的任何访问都有的访问权限。

    服务服务

    angular.js 中的服务与 winforms/wpf或者Silverlight中的服务非常相似。 它们是小 helper 类,可以提供跨应用程序使用的功能。 在像 C# 这样的强类型语言中,我们通常使这些服务实现特定的接口,并将它们注入到应用。 在测试中,我们可以为这些服务提供伪造/模拟,或者如果底层系统改变( 比如从Mongo数据库到Raven数据库存储),则提供替代版本

    虽然不支持接口( 虽然你可以用 TypeScript ),但它支持将真实/伪造服务注入它的代码。 实际上我想说的是 angular.js的主要要点是它支持IOC之外的IOC。

    模块

    然而,大多数应用程序都有一个主方法来实例化。连接和引导应用程序。 Angular 应用程序没有主要方法。 相反模块声明地指定了应用程序应该如何引导。 这里方法有以下几个优点:

    • 因此,这个过程更具说明性,更易于理解。
    • 在 单元测试 中不需要加载所有模块,这有助于编写单元测试。
    • 此外,可以在场景测试中加载其他模块,从而覆盖一些配置,并帮助end-to-end测试应用程序的运行情况。
    • 第三方代码可以作为重用模块进行封装。
    • 模块可以在任意/平行顺序( 由于 MODULE 执行的延迟特性) 中加载。

    http://docs.angularjs.org/guide/module

    推荐的方法是实际分割模块,这样你就可以拥有这样的结构:

    • 服务模块
    • 指令模块
    • 过滤器模块
    • 应用模块

    这就是如何定义 angular.js 插件模块,放弃使用angular.js 插件提供的功能" module"。

    angular.module('xmpl.service', []).
     value('greeter', {
     salutation: 'Hello',
     localize: function(localization) {
     this.salutation = localization.salutation;
     },
     greet: function(name) {
     returnthis.salutation + ' ' + name + '!';
     }
     }).
     value('user', {
     load: function(name) {
     this.name = name;
     }
     });

    依赖注入插件

    由于mocked版本可能会交换依赖注入( IOC ),因此很多基础架构可能被换掉了,或者使用mock服务测试控制器。 演示如何执行这里操作,或者如何测试不在本文范围内的 angular.js 命令行应用程序。 如果你想知道,访问 angular.js 文档,或者获取一本书。 抱歉

    以下模块示例,这是模块看起来像依赖的模块,在本例中,我们使用 2值'greeter'和'user',在'xmpl.service'模块中,我们使用了两个函数。 这个 MODULE 可以提供一个经过mock的'xmpl.service'模块版本。

    angular.module('xmpl', ['xmpl.service']).
     run(function(greeter, user) {
     // This is effectively part of the main method initialization code greeter.localize({
     salutation: 'Bonjour' });
     user.load('World');
     })

    路由

    web服务的主要框架是单个页面应用框架,因此具有视图模板概念,可以应用于响应所请求的特定路由。

    angular.js 路由实际上并不像在MVC或者 node.js ( ) 中路由那样,这是一个。

    路由是通过名为 $routeProvider的预生成服务完成的,该服务作为 angular.js 服务的一部分。 它允许用户使用一个非常简单的API来配置他们的路由,这将归结为以下 2个函数

  • when(path, route)
    • route 对象具有下列属性的位置
      • 控制器
      • 模板
      • templateUrl
      • 解析
      • redirectTo
      • reloadOnSearch
  • otherwise(params)
  • 下面是一个小例子

    $routeProvider
    . when('/products', {
     templateUrl: 'views/products.html',
     controller: 'ProductsCtrl' })
    . when('/about', {
     templateUrl: 'views/about.html' })
    . otherwise({ redirectTo: '/products' });;

    视图

    关于这个观点,没有太多的发言权。 我们以前可能都遇到过 html。 这就是视图所包含的内容。 唯一的区别是 angular.js 视图将包含其他( 非标准 html ) 绑定,允许视图模板显示来自 angular.js 对象范围对象的数据。 范围对象通常来自一个控制器( 虽然它不限于控制器,但是它可以被继承,或者通过指令来创建)。

    下面是一个小视图示例,注意使用的绑定,例如使用 ng-modelng-repeat,以及使用 angular.js 和,例如我将不会在本文中覆盖过滤器

    Search: <inputng-model="query">Sort by:<selectng-model="orderProp"><optionvalue="name">Alphabetical</option><optionvalue="age">Newest</option></select><ulclass="phones"><ling-repeat="phone in phones | filter:query | orderBy:orderProp"> {{phone.name}}
     <p>{{phone.snippet}}</p></li></ul>

    控制器

    控制器用于定义视图的范围。 作用域可以是视图可能使用的变量和函数,例如使用绑定。 下面是与我们刚刚看到的视图模板一起使用的控制器代码。

    function PhoneListCtrl($scope) {
     $scope.phones = [
     {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S.",
     "age": 0},
     {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet.",
     "age": 1},
     {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet.",
     "age": 2}
     ];
     $scope.orderProp = 'age';

    可以看到,控制器定义了以下 2个范围属性

    • phones: 哪个是 JSON array
    • orderProp: 哪个字符串值

    作用域

    范围是允许视图和控制器定义的范围对象属性/函数绑定在一起的粘附。 如果你曾经做过基于 WPF/Silverlight/WinRT的技术,比如,你可以将作用域视为 DataContext。 实际上,有相当多的UI框架具有类似概念的范围。 XAML技术具有通常是视图,而另一个流行的MVVM JavaScript库 knockout.js 类库也具有作用域,它使用各种预先生成的关键字在html中绑定了作用域和 heirarchical。

    angular.js 还支持嵌套/heirarchical范围,这有时会有些混淆。 在 personally angular.js 中,我发现使用插件的最佳方法是安装 Batarang插件,它可以使用作用域检查器( 类似于Silverlight的或者 SilverlightSpy ) 进行作用域

    这个图可以帮助巩固view-controller-scope的概念。

    Click Click Click Click Click

    指令

    angular.js 使用了一个非常新颖的概念,它被称为指令。 指令是聪明人,实际上允许你创建额外的属性,甚至是新的DOM Fragments。 这都是通过对指令应用某些约束来控制的,因这里你可以能希望将某个指令用作属性。 你可以将指令视为自定义控件。

    指令也遵循正常的 angular.js 规则,它们支持依赖注入,并且它们也可以被识别为范围。

    在撰写本文时,我遇到的最好的信息之一是 Bernardo Castilho: 在这里,我鼓励你阅读这篇文章,它是一篇优秀的文章,在结束之前,你将完全了解指令。

    总之,这是 angular.js 插件的基础,它现在与实际的演示应用程序代码演练。

    发布服务器

    就像前面提到的,发布服务器是一个WPF应用程序( 因此它是可以运行的EXE ),这并不是本文的主要主旨。 发布服务器的主要内容包括:

  • 这是使用令人惊叹的Fleck web socket 库与 angular.js web站点 talk
  • 它有Win8类型全景,所以你可以用鼠标滚动
  • 下面是WPF发布服务器在运行时应该显示的内容:

    现在,我们来看一个重要的部分,web。

    publicclass WebSocketInvoker : IWebSocketInvoker
    {
     List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
     WebSocketServer server = new WebSocketServer("ws://localhost:8181");
     public WebSocketInvoker()
     {
     FleckLog.Level = LogLevel.Debug;
     server.Start(socket => {
     socket.OnOpen = () => {
     Console.WriteLine("Open!");
     allSockets.Add(socket);
     };
     socket.OnClose = () => {
     Console.WriteLine("Close!");
     allSockets.Remove(socket);
     };
     socket.OnMessage = Console.WriteLine;
     });
     }
     publicvoid SendNewMessage(string jsonMessage)
     {
     foreach (var socket in allSockets)
     {
     socket.Send(jsonMessage);
     }
     }
    }

    这其实就是那部分,非常酷,(。感谢 Fleck web socket 库)。 now realise realise,我想在网上 concentrate,这篇文章很适合你,但我想用一个原始的网页套接字,那就是我想用的那篇文章,perfectly。

    在这个代码中,当用户点击一个图像时就会调用 SendNewMessage,并且点击的图像名称将通过web套接字发送到 angular.js web站点。 我在网站上已经有可能的图片,所以我选择了发布服务器和 angular.js的文件。显然,我选择了发布服务器和web站点都知道这个示例应用程序/文章的目的。

    angular.js 网站

    本节将讨论附加的演示代码 angular.js 网站的细节。 如果你到这一点,我提到的一些东西在你看到一些代码时就开始有意义了。

    Require.js 用法

    在开始查看 angular.js 插件之前,我使用Require.js 插件,它是一个JavaScript加载框架,它允许你指定依赖关系和首选模块加载顺序。 我在另一篇文章中写了这个,你可以在这里阅读: 模块化Javascript使用 Require.js

    在本文中我已经构建了一些 apon ( angular.js book附带的源代码kick一些 kickhttps://github.com/shyamseshadri/angularjs-book )

    如果你愿意,你可以在这个主题上做更多的阅读,但是让我们看看,看看附加的angular.js 网站的内容是什么。

    它从主 angular.js 页面( Index.html ) 中的这种代码开始:

    查看 index.html

    <html>.....<scriptdata-main="scripts/main"src="scripts/vendor/require.js"></script></html>

    这是标准 Require.js 代码,告诉Require.js,它是应该运行的主要 Bootstrap 代码文件。 可以看到,这是 scripts/main,所以现在我们来看看

    查看 scriptsmain.js

    // the app/scripts/main.js file, which defines our RequireJS configrequire.config({
     paths: {
     angular: 'vendor/angular.min',
     jqueryUI: 'vendor/jquery-ui',
     jqueryColorbox: 'vendor/jquery-colorbox',
     jquery: 'vendor/jquery',
     domReady: 'vendor/domReady',
     reactive: 'vendor/rx' },
     shim: {
     angular: {
     deps: ['jquery', 'jqueryUI', 'jqueryColorbox'],
     exports: 'angular' },
     jqueryUI: {
     deps: ['jquery']
     },
     jqueryColorbox: {
     deps: ['jquery']
     }
     }
    });
    require([
     'angular',
     'app',
     'domReady',
     'reactive',
     'services/liveUpdatesService',
     'services/imageService',
     'services/localStorageService',
     'controllers/rootController',
     'controllers/favsController',
     'directives/ngbkFocus',
     'directives/draggable',
     'directives/resizable',
     'directives/tooltip',
     'directives/colorbox'// Any individual controller, service, directive or filter file// that you add will need to be pulled in here.],
     function (angular, app, domReady) {
    . . .....
    . . .....
    . . .....
    . . .....
     }
    );

    在 here.It 上进行了相当多的工作,然而在 3个部件中

  • 我们使用JavaScript文件所在的路径配置 Require.js 插件
  • 我们使用 Require.jsRequire.js 配置一个首选负载订单。 shim 本质上设置了库要加载的依赖项
  • 然后我们使用 Require.js [Require] 来告诉 angular.js 应用程序我们希望满足哪些依赖。
  • 我还使用了 Require.js 插件来满足演示应用程序的控制器要求。 下面是一个示例:

    define(['controllers/controllers',
     'services/imageService',
     'services/utilitiesService',
     'services/localStorageService'],
     function (controllers) {
     controllers.controller('FavsCtrl',
     ['$window',
     '$scope',
     'ImageService',
     'UtilitiesService',
     'LocalStorageService',
     function (
     $window,
     $scope,
     ImageService,
     UtilitiesService,
     LocalStorageService) {
    . . ....
    . . ....
    . . ....
    . . ....
    . . ....
     }]);
    });

    主应用程序设置

    查看 scriptsmain.js

    现在你已经看到了主引导代码( 它主要由 Require.js 插件配置所占用),让我们快速看一下实际的angular.js 引导位( bootstrapping )。

    这就是我们在本文开头讨论的一点,你知道实际使附加代码的" angular.js"应用程序的位。

    部分如下所示:

    function (angular, app, domReady) {
     'use strict';
     app.config(['$routeProvider',
     function ($routeProvider) {
    . . ..
    . . ..
    . . ..
     }]);
     domReady(function () {
     angular.bootstrap(document, ['MyApp']);
     // The following is required if you want AngularJS Scenario tests to work $('html').addClass('ng-app: MyApp');
     });
    }

    这个引导完成了 2件事:

  • 它将设置可用的有效路由,我们将在下一步查看
  • 它依赖一个特殊的angular.js 插件插件works它与jQuery的工作方式非常相似,它的性能与
    ready()
    事件 works。 dom准备好之后,"html"元素被归为使它充当 angular.js 应用程序的属性。
  • 还有一个问题," MyApp"MODULE 是从哪里来的。 在这里引导之前谁创造了它?

    这个问题的答案是,它位于它自己的文件" app.js"中,看起来像这样

    查看 scriptsapp.js

    // The app/scripts/app.js file, which defines our AngularJS appdefine(['angular', 'controllers/controllers', 'services/services', 'filters/filters', 'directives/directives'], function (angular) {
     return angular.module('MyApp', ['controllers', 'services', 'filters', 'directives']);
    });

    路由路径。

    查看 scriptsmain.js

    demo应用程序有 3个有效路由,每个路由都使用标准的 angular.js $routeProvider 服务配置,其中所有设置代码都在boostrapping文件 main.js 中执行。

    unction ($routeProvider) {
     $routeProvider
    . when('/', {
     templateUrl: 'views/root.html',
     controller: 'RootCtrl' })
    . when('/favs', {
     templateUrl: 'views/favs.html',
     controller: 'FavsCtrl' })
    . when('/about', {
     templateUrl: 'views/about.html' }).otherwise({ redirectTo: '/' });;
    }

    我认为有 3个路由可以说是 上面,以及如何配置它们。 所以我不会再说了。

    root 页

    这是我在演示网站中放置的最复杂的页面,因为它带来了很多不同的内容。

    那么这个页面到底能做什么?

    这个想法是有一个称为" LiveUpdatesService"的服务,它监听了is的客户端端口,该服务将数据推出。 LiveUpdatesService 为JavaScript使用React性扩展来提供可能被订阅的数据流。

    这个页面将会订阅这个pulished流,每次看到新的条目时,它就会添加一个新的 jQuery UI 元素,可以拖动的/可以调整大小的UI元素,该元素还没有显示所显示的元素。

    它还允许用户将图像保存到 HTML 5本地存储,并将它们从本地存储中删除。 如果本地存储中有aready项,它们的详细信息将用作 root 页的初始起始状态。 我得说这看起来很酷,因为所有的信息都是持久的,所以它记住了大小。位置。

    所以一般来说,root 页面就是这样做的。

    这就是 root 页面看起来像什么

    Click Click Click Click Click

    这就是它的样子,想看一些代码?

    LiveUpdatesService

    这是从发布者web套接字中侦听传入数据的服务,并通过 Subject 对象的无功扩展推出新的for数据。 下面是该服务的代码:

    define(['services/services'],
     function (services) {
     services.factory('LiveUpdatesService', ['$window',
     function (win) {
     var subject = new Rx.Subject();
     if ("WebSocket"in window) {
     // create a new websocket and connectvar ws = new WebSocket('ws://localhost:8181/publisher', 'my-protocol');
     // when data is comming from the server, this metod is called ws.onmessage = function (evt) {
     subject.onNext(evt.data);
     };
     // when the connection is established, this method is called ws.onopen = function () {
     win.alert('Websocket connection opened');
     };
     ////when the connection is closed, this method is called ws.onclose = function () {
     subject.onError('Websocket connection closed, perhaps you need to restart the Publisher, and refresh web site');
     };
     }
     return {
     publishEvent: function (value) {
     subject.onNext(value);
     },
     eventsStream: function () {
     return subject.asObservable();
     }
     };
     }]);
     });

    这是使用React性扩展的代码,我们先检查我们是否看到了一个带有相同 NAME的项目,如果我们只是将一条消息显示到用户的( 要注意的是,我们用收费 window,而是使用 $window Angular 服务( 可能会更容易被模仿) ) 中。

    如果以前没有看到图像 NAME,则使用我们随机定位的ImageService 创建一个新项目。

    LiveUpdatesService.eventsStream().subscribe(
     function (data) {
     if ($location.path() == '/') {
     var idx = $scope.imageitems.propertyBasedIndexOf('name', data);
     if (idx> = 0) {
     $window.alert('An item with that name has already been added');
     } else {
     var randomLeft = UtilitiesService.getRandomInt(10, 600);
     var randomTop = UtilitiesService.getRandomInt(10, 400);
     var randomWidth = UtilitiesService.getRandomInt(100, 300);
     var randomHeight = UtilitiesService.getRandomInt(100, 300);
     $scope.imageitems.push(ImageService.createImageItem(
     data, randomLeft, randomTop, randomWidth, randomHeight, false));
     $scope.$apply();
     }
     }
     },
     function (error) {
     $window.alert(error);
     });

    LocalStorageService

    这里服务负责从 HTML 5本地存储中持久化/获取数据项。 我认为这段代码是非常自我解释的,所以我将把它放在下面:

    define(['services/services'],
     function (services) {
     services.factory('LocalStorageService', [
     function () {
     return {
     isSupported: function () {
     try {
     return'localStorage'in window && window['localStorage']!== null;
     } catch (e) {
     returnfalse;
     }
     },
     save: function (key, value) {
     localStorage[key] = JSON.stringify(value);
     },
     fetch: function (key) {
     return localStorage[key];
     },
     parse: function(value) {
     return JSON.parse(value);
     },
     clear: function (key) {
     localStorage.removeItem(key);
     }
     };
     }]);
     });

    ImageService

    这个服务只为 root 页面创建 ImageItem 对象,为Favs页面创建 FavItem 对象。

    function ImageItem(name, left, top, width, height, isFavourite) {
     var self = this;
     self.name = name;
     self.left = left;
     self.top = top;
     self.width = width;
     self.height = height;
     self.isFavourite = isFavourite;
     self.styleProps = function () {
     return {
     left: self.left + 'px',
     top: self.top + 'px',
     width: self.width + 'px',
     height: self.height + 'px',
     position: 'absolute' };
     };
     return self;
    };function FavImageItem(name) {
     var self = this;
     self.name = name;
     return self;
    };
    define(['services/services'],
     function (services) {
     services.factory('ImageService', [
     function () {
     return {
     createImageItem: function (name, left, top, width, height, isFavourite) {
     returnnew ImageItem(name, left, top, width, height, isFavourite);
     },
     createFavImageItem: function (name) {
     returnnew FavImageItem(name);
     }
     };
     }]);
     });

    要注意的一点是,动态CSS是如何在 angular.js 中完成的。 要实现对象更改时更新的动态 CSS,需要提供一个函数,这就是 styleProps() 函数中可以看到的:

    self.styleProps = function () {
     return {
     left: self.left + 'px',
     top: self.top + 'px',
     width: self.width + 'px',
     height: self.height + 'px',
     position: 'absolute' };
    };

    如果在JSON对象上进行更新,那么html也会反映这种情况。 这不是很容易找到,所以要确保你读了几次,固化了这些知识,把它固定在那里。

    ng-style="imageitems[$index].styleProps()"

    UtilitiesService

    这里服务提供以下功能:

    • 为数组添加一个 propertyBasedIndexOf(),它允许在将索引返回的特定项属性中搜索 array。
    • getRandomInt(): 用于获取随机 X/Y 点以在它的显示的1st 时间内放置新的图像项
    • delayedAlert(): 在某些延迟时间后显示警告

    下面是代码:

    define(['services/services'],
     function (services) {
     services.factory('UtilitiesService', [
     function () {
     var initialised = false;
     return {
     addArrayHelperMethods: function () {
     if (!initialised) {
     initialised = true;
     Array.prototype.propertyBasedIndexOf = function arrayObjectIndexOf(property, value) {
     for (var i = 0, len = this.length; i <len; i++) {
     if (this[i][property] === value) return i;
     }
     return -1;
     };
     }
     },
     getRandomInt: function (min, max) {
     return Math.floor(Math.random() * (max - min + 1)) + min;
     },
     delayedAlert: function(message) {
     setTimeout(function () {
     $window.alert(message);
     }, 1000);
     }
     };
     }]);
     });

    可以拖动指令

    To,我已经知道必须使用 jQuery UI 库,但是在使用 angular.js 时,有一个 definateangular.js way way jQuery jQuery代码littering代码 certainly littering。 那么我们有什么选择呢。 这就是 angular.js的指令适合的地方,它们被设计用来替换和增强 DOM,这就是指令所做的。

    所以每当你需要直接修改DOM时,你应该考虑使用 angular.js 指令。

    这就是创建小型 jQuery UI 指令的简单方法,可以在 <表中看到。 可以拖动的可以拖动的>。 标记中的</表> table 标记。

    下面是 draggable 指令代码,可以看到这只限于属性使用,并简单地将工作委托给实际的 jQuery UI ( )。

    值得注意的一点是,一旦拖动完成,我想通知控制器新的位置值,这样它们就可以反映。 既然定位是在 angular.js - 控制器范围外完成的,我们需要获得 draggable 指令来更新控制器范围,这样它就会知道它的某些东西已经更改了其中一个变量。 我们使用 jQuery UI 可以通过使用 angular.js 来实现这个功能,这就是我们可以使用

    define(['directives/directives'], function (directives) {
     directives.directive('draggable', ['$rootScope', function ($rootScope) {
     return {
     restrict: 'A',
     //may need the model to be passed in here so we can apply changes to its left/top positions link: function (scope, element, attrs) {
     element.draggable(
     {
     stop: function (event, ui) {
     scope.$apply(function() {
     scope.updatePosition(
     scope.imageitem.name,
     {
     left: ui.position.left,
     top: ui.position.top
     }
     );
     });
     }
     });
     }
     };
     }]);
    });

    当指令调用到控制器的范围时调用的控制器代码

    // NOTE: $scope.$apply is called by the draggable directive$scope.updatePosition = function (name, pos) {
     var idx = $scope.imageitems.propertyBasedIndexOf('name', name);
     var foundItem = $scope.imageitems[idx];
     foundItem.left = pos.left;
     foundItem.top = pos.top;
    };

    可以调整大小的指令

    resize指令与可以拖动指令非常类似,它是另一个 jQuery UI 基于 angular.js 指令。 下面是它的代码:

    define(['directives/directives'], function (directives) {
     directives.directive('resizable', ['$rootScope', function ($rootScope) {
     return {
     restrict: 'A',
     //may need the model to be passed in here so we can apply changes to its left/top positions link: function (scope, element, attrs) {
     element.resizable(
     {
     maxHeight: 200,
     minHeight: 100,
     //aspectRatio: 16/9, stop: function (event, ui) {
     scope.$apply(function () {
     scope.updateScale(
     scope.imageitem.name,
     {
     top: ui.position.top,
     left: ui.position.left
     },
     {
     width: ui.size.width,
     height: ui.size.height
     }
     );
     });
     }
     });
     }
     };
     }]);
    });

    在我们改变( 用户界面元素的比例) angular.js 控制器的知识之外,我们需要得到指令来更新控制器作用域,下面是相关代码:

    // NOTE: $scope.$apply is called by the resizable directive$scope.updateScale = function (name, pos, size) {
     var idx = $scope.imageitems.propertyBasedIndexOf('name', name);
     var foundItem = $scope.imageitems[idx];
     foundItem.left = pos.left;
     foundItem.top = pos.top;
     foundItem.width = size.width;
     foundItem.height = size.height;
    };

    root 控制器

    root 控制器的一些内部内容已经被覆盖,所以我将从已经介绍的函数中删除内部代码:

    define(['controllers/controllers',
     'services/liveUpdatesService',
     'services/utilitiesService',
     'services/imageService',
     'services/localStorageService'],
     function (controllers) {
     controllers.controller('RootCtrl',
     ['$window',
     '$scope',
     '$location',
     'LiveUpdatesService',
     'UtilitiesService',
     'ImageService',
     'LocalStorageService',
     function (
     $window,
     $scope,
     $location,
     LiveUpdatesService,
     UtilitiesService,
     ImageService,
     LocalStorageService) {
     $scope.imageitems = [];
     $scope.imageItemsStorageKey = 'imageItemsKey';
     //load existing items from local storage which looks cool, as they show up in their persisted//positions again...Coolif (LocalStorageService.isSupported()) {
     var currentFavs = LocalStorageService.fetch($scope.imageItemsStorageKey);
     if (currentFavs!= undefined) {
     currentFavs = JSON.parse(currentFavs);
     for (var i = 0; i <currentFavs.length; i++) {
     var favItem = currentFavs[i];
     $scope.imageitems.push(ImageService.createImageItem(
     favItem.name, favItem.left, favItem.top, favItem.width, favItem.height, true));
     }
     }
     }
     UtilitiesService.addArrayHelperMethods();
     LiveUpdatesService.eventsStream().subscribe(
    . . ...
    . . ...
    . . ...
     );
     $scope.addToFavourites = function (index) {
     if (!LocalStorageService.isSupported()) {
     $window.alert('Local storage is not supported by your browser, so saving favourites isn't possible');
     } else {
     var currentStoredFavsForAdd = LocalStorageService.fetch($scope.imageItemsStorageKey);
     if (currentStoredFavsForAdd == undefined) {
     currentStoredFavsForAdd = [];
     } else {
     currentStoredFavsForAdd = JSON.parse(currentStoredFavsForAdd);
     }
     var scopeImageItem = $scope.imageitems[index];
     var favsIdx = currentStoredFavsForAdd.propertyBasedIndexOf('name', scopeImageItem.name);
     if (favsIdx> = 0) {
     $window.alert('An item with that name is already in your favourites.');
     return;
     }
     $scope.imageitems[index].isFavourite = true;
     currentStoredFavsForAdd.push(scopeImageItem);
     LocalStorageService.save($scope.imageItemsStorageKey, currentStoredFavsForAdd);
     $window.alert('Saved to favourites');
     }
     };
     $scope.removeFromFavourites = function (index) {
     if (!LocalStorageService.isSupported()) {
     $window.alert('Local storage is not supported by your browser, so removing from favourites isn't possible');
     } else {
     var currentStoredFavsForRemoval = LocalStorageService.fetch($scope.imageItemsStorageKey);
     if (currentStoredFavsForRemoval == undefined) {
     return;
     } else {
     currentStoredFavsForRemoval = JSON.parse(currentStoredFavsForRemoval);
     }
     var scopeImageItem = $scope.imageitems[index];
     var favsIdx = currentStoredFavsForRemoval.propertyBasedIndexOf('name', scopeImageItem.name);
     $scope.imageitems.splice(index, 1);
     if (favsIdx> = 0) {
     currentStoredFavsForRemoval.splice(favsIdx, 1);
     LocalStorageService.save($scope.imageItemsStorageKey, currentStoredFavsForRemoval);
     }
     $window.alert('Item removed from favourites');
     }
     };
     // NOTE: $scope.$apply is called by the draggable directive $scope.updatePosition = function (name, pos) {
    . . ...
    . . ...
    . . ...
     };
     // NOTE: $scope.$apply is called by the resizable directive $scope.updateScale = function (name, pos, size) {
    . . ...
    . . ...
    . . ...
     };
     }]);
    });

    可以看到,控制器的大多数 root 代码已经被覆盖了,所以还要讨论?

    实际上,剩下的代码执行以下操作:

  • 允许用户使用图像平铺用户界面中的按钮来调用 addToFavourites 函数( 它将把它添加到 HTML 5本地存储)
  • 允许用户使用图像平铺用户界面中的按钮来调用 removeFromFavourites 函数( 它将从UI中删除它,也将从 HTML 5本地存储中删除)
  • 当首次呈现页面时,将从 HTML 5本地存储中读取所有项及它的持久状态。
  • root 视图

    这个视图很容易,因为大多数实际工作都是由各种服务和控制器完成的。 下面是 root 视图标记:

    <divng-repeat="imageitem in imageitems"><tabledraggableresizableclass="imageHolder, imageDropShadow"ng-style="imageitems[$index].styleProps()"><tr><tdclass="imageHeader"> {{imageitem.name}}</td></tr><tr><tdalign="center"><imgng-src="http://www.codeproject.com/app/images/{{imageitem.name}}"class="imageCell"/></td></tr><tr><tdalign="center"><imgsrc="http://www.codeproject.com/app/images/favIcon.png"width="25%"class="favIcon"tooltiphref=""title="Save To Favourites"ng-click="addToFavourites($index)"/><imgsrc="http://www.codeproject.com/app/images/favDelete.png"width="25%"class="favIcon"title="Remove From Favourites"tooltipng-click="removeFromFavourites($index)"ng-show="imageitems[$index].isFavourite"/></td></tr></table></div>

    最喜欢的页面。

    虽然不像 root 页面那样复杂,但它的最复杂的页面是 2nd,因这里很可以能有一点解释。

    那么这个页面到底能做什么?

    这个想法是在( 可以是一个空的集合) 5本地存储中存储的一个图像数据集的集合。 当收到收藏夹视图时,将检查这里 HTML 5本地存储的数据。 用户还可以点击任何一个缩略图来启动ColorBox插件插件。

    这是在本地存储中保存某些项目时,收藏夹页面的外观。

    Click Click Click Click Click

    这就是当你点击thumnbails的时候,它是什么样子

    那么这个页面是如何工作的呢。 它的中一个难点是你可能会认为这是一件非常简单的事情。 所以在本地存储中,我们有一个 1的JSON字符串,我想将它转换为一个三维的table 布局,我可以使用 angular.js的ng-repeat 绑定来使用它。

    Favs控制器

    让我们先看看控制器。

    define(['controllers/controllers',
     'services/imageService',
     'services/utilitiesService',
     'services/localStorageService'],
     function (controllers) {
     controllers.controller('FavsCtrl',
     ['$window',
     '$scope',
     'ImageService',
     'UtilitiesService',
     'LocalStorageService',
     function (
     $window,
     $scope,
     ImageService,
     UtilitiesService,
     LocalStorageService) {
     $scope.imageItemsStorageKey = 'imageItemsKey';
     $scope.favImageItems = [];
     $scope.columnCount = 5;
     $scope.favText = '';
     $scope.shouldAlert = false;
     $scope.tableItems = [];
     while ($scope.tableItems.push([]) <$scope.columnCount);
     if (!LocalStorageService.isSupported()) {
     $scope.favText = 'Local storage is not supported by your browser, so viewing favourites isn't possible';
     $scope.shouldAlert = true;
     } else {
     var currentStoredFavs = LocalStorageService.fetch($scope.imageItemsStorageKey);
     var currentFavs = [];
     if (currentStoredFavs!= undefined) {
     currentFavs = JSON.parse(currentStoredFavs);
     }
     if (currentFavs.length == 0) {
     $scope.favText = 'There are no favourites stored at the moment';
     $scope.shouldAlert = true;
     } else {
     var maxRows = Math.ceil(currentFavs.length/$scope.columnCount);
     $scope.favText = 'These are your currently stored favourites. You can click on the images to see them a bit larger';
     if (currentFavs.length <$scope.columnCount) {
     $scope.tableItems[0] = [];
     for (var i = 0; i <currentFavs.length; i++) {
     $scope.tableItems[0].push(ImageService.createFavImageItem(currentFavs[i].name));
     }
     } else {
     var originalIndexCounter = 0;
     for (var r = 0; r <maxRows; r++) {
     for (var c = 0; c <$scope.columnCount; c++) {
     if (originalIndexCounter <currentFavs.length) {
     $scope.tableItems[r][c] =
     ImageService.createFavImageItem(currentFavs[originalIndexCounter].name);
     originalIndexCounter++;
     }
     }
     }
     }
     }
     if ($scope.shouldAlert) {
     UtilitiesService.delayedAlert($scope.favText);
     }
     }
     }]);
    });

    可以看到,这里的大部分工作是从 HTML 5本地存储获取数据,并从字符串表示转换为 JSON 1维 array,然后将它的转换为可以在标记内部绑定的2 dimenionsal结构。

    这里还有一些其他的注意事项:

    • 我们使用 angular.js$window 而不是" window"来允许用mock代替
      $window
      服务
    • 我们利用前面看到的LocalStorageService
    • 我们利用前面看到的UtilitiesService
    • 我们利用前面看到的ImageService

    Favs视图

    在控制器中完成的所有繁重工作中,视图标记非常微小:

    <divclass="infoPageContainer"><h2>Favourites</h2><p>{{favText}}</p><tableid="favsTable"><trng-repeat="row in tableItems"><tdng-repeat="cell in row"><acolorboxtitle="{{cell.name}}"ng-href="http://www.codeproject.com/app/images/{{cell.name}}"><imgng-src="http://www.codeproject.com/app/images/{{cell.name}}"class="favSmallIcon"/></a></td></tr></table></div>

    在你的范围中,一旦有正确的结构,你就会发现,在 angular.js 中执行 table 布局是多么简单。

    ColorBox指令

    拼图中的final 部分是如何将这些项目变成一个 jQuery ColorBox。 知道我们现在所知道的,我们应该能够意识到,对于另一个指令来说,这个答案是。

    是的,你猜到它是一个c olorbox 指令,可以在 <a 中看到。 收费为 colorbox。 标记中的</一个> 标记标记。

    下面是 colorbox 指令代码,你可以看到这限制了属性使用,只是简单地将工作委托给 jQuery ColorBox ( 在 Require.js 中被引用),否则 angular.js 插件就不会启动,否则插件将不会启动

    define(['directives/directives'], function (directives) {
     directives.directive('colorbox', ['$rootScope', function ($rootScope) {
     return {
     restrict: 'A',
    //may need the model to be passed in here so we can apply changes to its left/top positions
     link: function (scope, element, attrs) {
     $(element).colorbox({ rel: 'group3', transition:"elastic", width:"50%", height:"50%" });
     }
     };
     }]);
    });

    关于页面

    about页面只是 static 文本,所以这里没有什么 groovy。 我添加了这个页面,以便在演示应用程序中有足够的路由使它更加完整。 这里的完整性是关于页面的屏幕截图

    "

    Click Click Click Click Click

    ,那是什么

    总之,我现在想说的就是,希望你们喜欢这篇文章,从中获得一些东西。 我知道我自己。 这是一个很难写的方法,因为它有一些新的概念,我对最终结果很满意。 如果你喜欢读/看的内容,并且感觉留下投票/评论将会很酷。

    总之,直到下一个,希望不会像这个时候一样长。


angular  
相关文章