示例可重用的web component方式组织angular应用模块
在online web应用中,经常有这样的需求,能够让用户通过浏览器来输入代码,同时能够根据不同的代码来做语法高亮。大家已知有很多相应的javascript库来实现语法高亮的功能,比如codemirror就是一个不错的选择。而我们使用angular开发web应用,那么就希望能够使用directive来实现这个功能,以便能够很好的重用。https://www.polymer-project.org/ 可以得到更多可重用web组件的信息
下面是如何使用我们的 <code-editor> 的:
<html ng-app="demo">
<head>
<title>Posts</title>
</head>
<body>
<code-editor syntax="javascript" ng-model="content.code">
var sum = function (a, b) {
return a + b;
}
</code-editor>
<textarea ng-model="content.code" cols="100" rows="50"></textarea>
</body>
</html>
这个directive的目标是:像 <pre> 元素一样接受接受输入代码文本,同时能够和 <ngModel> 一样将输入文本作为model放到变量中去。该directive同时也需要将代码在codemirror代码编辑器中展示。
首先我们来创建基本的文件夹结构。我们创建一个components/codeEditor目录作为我们整个code editor组件的工作目录。在这个目录中,我们将该组件所用到的javascript库(实际就是codemirror库)以及css文件放到vendor目录中。创建一个新的codeEditor.js作为directive代码,一个code-editor.html模板也放在component根目录中。
使用这种方式来组织代码实际上就是在遵循web component开发的模式了。现在在code-editor.html模板文件的div元素上初始化codeMirror作为开始。
code-editor.html:
<div class="code-editor"></div>
codeEditor.js:
angular.module("demo").directive("codeEditor", function(){
return {
restrict: "E",
replace: true,
scope: {
syntax: "@",
theme: "@"
},
templateUrl: "components/codeEditor/code-editor.html",
link: function(scope, element, attrs) {
var editor = CodeMirror(element[0], {
mode: scope.syntax || "javascript",
theme: scope.theme || "vibrant-ink",
lineNumbers: true
});
}
};
});
在上述js代码中,调用codeMirror函数使得div元素具有codeMirror的代码高亮功能,同时lineNumber显示出来。这时已经具有了代码输入和高亮的功能:
这时代码编辑器已经工作了,但是你发现我们在使用code-editor directive的html文件中的代码却并没有被渲染。这是因为,默认情况下,angular将丢弃code-editor元素的内容,替而代之为该directive的template:code-editor.html的内容。为了让angular能将包含在原始code-editor元素内的内容保存并使用起来,我们需要设置code-editor元素的transclude属性为true.
另外一点是:我们不准备使用 ng-transclude directive来插入内容。反而,我们将执行一个手动的transclude,以便允许内容直接传递到editor。下面是相关代码:
codeEditor.js:
angular.module("demo").directive("codeEditor", function(TextUtils){
return {
restrict: "E",
replace: true,
transclude: true,
scope: {
syntax: "@",
theme: "@"
},
templateUrl: "components/codeEditor/code-editor.html",
link: function(scope, element, attrs, ctrl, transclude) {
var editor = CodeMirror(element[0], {
mode: scope.syntax || "javascript",
theme: scope.theme || "vibrant-ink",
lineNumbers: true
}); transclude(function(clonedEl){
var initialText = TextUtils.normalizeWhitespace(clonedEl.text());
editor.setValue(initialText);
});
}
};
});
上述代码中,当transclude属性被设置为true,我们在link函数中就有了第5个参数--transclude函数。该函数有几种不同的用法,在我们的例子中,我们将传入一个callback函数作为第一个参数。这个callback被调用时将被传入一个原始transcluded content作为参数,这样我们就可以访问到那块内容并且被传递给editor去。TextUtils是一个简单的服务,半酣一个normlizeWhitespace函数,该函数可以清除leading whitespace.
最后一件事情是我们需要让ngModel可以和editor工作起来,这样我们就可以将他和input,textarea等绑定起来。第一步,我们需要require ngModel属性。
angular.module("demo").directive("codeEditor", function(TextUtils){
return {
restrict: "E",
replace: true,
require: "?ngModel",
transclude: true,
scope: {
syntax: "@",
theme: "@"
},
templateUrl: "components/codeEditor/code-editor.html",
link: function(scope, element, attrs, ngModelCtrl, transclude) { ... }
};
}); // ....
通过设置require属性,我们告知这个directive从ngModel中包含controller的引用到link函数中。通过增加一个?在directive名称前,我们意味着这是一个选项,以便阻止angular在ngModel并不存在的情况下抛出异常。既然我们在directive的link函数中已经可以访问ngModel的controller了,我们需要了解几个用于同步数据到model的几个函数:
- ngModelCtrl.$setViewValue(someValue)
$setViewValue函数用于在model上赋值。当editor的内容变化时,我们需要调用该函数。
- ngModelCtrl.$render
$render属性需要被赋一个函数值。这个函数是一个当model value变化时调用的callback。注意model的value并不会传递到这个函数中去。一旦model的value发生变更时,我们需要设置editor的内容为model的value
- ngModelCtrl.$viewValue
$viewValue属性包含model的当前值。每当$render回调被调用时我们需要使用它设置editor的value。
看看下面的代码:
angular.module("demo").directive("codeEditor", function($timeout, TextUtils){
return {
restrict: "E",
replace: true,
require: "?ngModel",
transclude: true,
scope: {
syntax: "@",
theme: "@"
},
templateUrl: "components/codeEditor/code-editor.html",
link: function(scope, element, attrs, ngModelCtrl, transclude){
var editor = CodeMirror(element[0], {
mode: scope.syntax || "javascript",
theme: scope.theme || "default",
lineNumbers: true
}); if(ngModelCtrl) {
$timeout(function(){
ngModelCtrl.$render = function() {
editor.setValue(ngModelCtrl.$viewValue);
}
})
} transclude(function(clonedEl){
var initialText = TextUtils.normalizeWhitespace(clonedEl.text());
editor.setValue(initialText); if(ngModelCtrl){
$timeout(function(){
if(initialText && !ngModelCtrl.$viewValue){
ngModelCtrl.$setViewValue(initialText);
} editor.on('change', function(){
ngModelCtrl.$setViewValue(editor.getValue());
});
});
}
}); scope.$on('$destroy', function(){
editor.off('change');
});
}
}
});
当model变化时,既然我们使得require ngModel为可选而非必选,我们需要确保ngModel controller是否确实存在。在$render函数中,我们将model的value使用$viewValue属性赋值到editor的contents中去。这将避免一个Undefined value被设置到editor中去。
每当editor变更时,我们设置model的value。同时我们使用一个$timeout来调用它是因为为了等待model初始化。
最后我们删除和editor关联的用于更新model的event handler。当你使用非angular事件时,他们需要在$destroy回调中被清除。这将确保directive完全清除避免memory leak。
https://www.codeschool.com/blog/2015/03/06/digging-advanced-angularjs-directives/
示例可重用的web component方式组织angular应用模块的更多相关文章
- 使用纯粹的JS构建 Web Component
原文链接:https://ayushgp.github.io/htm...译者:阿里云 - 也树 Web Component 出现有一阵子了. Google 费了很大力气去推动它更广泛的应用,但是除 ...
- Web Component探索
概述 各种网站往往需要一些相同的模块,比如日历.调色板等等,这种模块就被称为“组件”(component).Web Component就是网页组件式开发的技术规范. 采用组件进行网站开发,有很多优点. ...
- Web Component总结
Web Component 一个Web组件通常由四个部分组成:模板.Shadow DOM.自定义元素与打包,其中Shadow DOM解决了组件在页面中的封装问题 Shadow DOM 有shadow ...
- Web Component
前言 Web Component不是新东西,几年前的技术,但是受限于浏览器兼容性,一直没有大规模应用在项目里,直到现在(2018年年末),除IE仍不支持之外,其它主流浏览器都支持Web Compone ...
- WCF服务的Web HTTP方式
NET 3.5以后,WCF中提供了WebGet的方式,允许通过url的形式进行Web 服务的访问.现将WCF服务设置步骤记录如下: endpoint通讯协议设置成 webHttpBinding en ...
- Web Component 文章
周末无意中了解了Web Component的概念. http://blog.amowu.com/2013/06/web-components.html http://www.v2ex.com/t/69 ...
- hadoop笔记之Hive的管理(web界面方式)
Hive的管理(二) Hive的管理(二) Web界面方式 端口号9999 启动方式:hive --service hwi 通过浏览器来访问:http://<IP地址>:9999/hwi/ ...
- js Web存储方式
JSON是数据交互中最常用的一种数据格式. 由于各种语言的语法都不同,在传递数据时,可以将自己语言中的数组.对象等转换为JSON字符串> 传递之后,可以讲JSON字符串,在解析为JSON对象. ...
- Salesforce知识整理(一)之Lightning Web Component Tools
目录 LWC知识整理(一) 工具 Salesforce CLI Visual Studio Code(VS Code) Developer Hub(Dev Hub) 开启Dev Hub 相关资料 茶余 ...
随机推荐
- HDU4542 小明系列故事——未知剩余系
大赞的数论题: 大致思路: 对于TYPE=1的情况,认为 X 中有 X-K个约数,求最小的X,X-K>0 那么化为B+K的约数为B, 我们知道(B+K)的约数<=2*SQRT(B+K);这 ...
- ASP.NET页面优化性能提升方法记录
今天与大家分享:一种优化页面执行速度的方法.采用这个方法,可以使用页面的执行速度获得[8倍]的提升效果. 为了让您对优化的效果有个直观的了解,我准备了下面的测试结果截图: 测试环境:1. Window ...
- 翻译 - 元编程动态方法之public_send
李哲 - MAY 20, 2015 原文地址:Metaprogramming Dynamic Methods: Using Public_send 作者:Friends of The Web的开发者V ...
- (转)Eclipse平台技术概述
转载:周金根 http://zhoujg.blog.51cto.com/1281471/516833 Eclipse:Eclipse平台技术概述 2010-10-19 13:35:00 标签:E ...
- Lucene教程--转载
Lucene教程 1 lucene简介1.1 什么是lucene Lucene是一个全文搜索框架,而不是应用产品.因此它并不像www.baidu.com 或者google Desktop那么拿来 ...
- win7建wifi 热点,附wifi小工具
首先申明:1)以下操作均在管理员身份下操作,其他用户下请亲测. 2)具备无线网卡,并且已经安装好了驱动. 1.打开命令行:输入netsh wlan set hostedn ...
- 三、Android NDK编程预备之Java jni入门创建C/C++共享库
转自: http://www.eoeandroid.com/thread-264971-1-1.html 应网友回复,答应在两天前要出一篇创建C/C++共享库的,但由于清明节假期,跟朋友出去游玩,丢手 ...
- YARN集群维护部分问题汇总
云梯开发人员在云梯Yarn集群的搭建和维护过程中做了许多工作,本文选择这期间部分较为典型的问题,通过对这些问题的分析和解决方案,为大家分享分布式系统问题调查的经验. 调查的问题 1. 2013年初引入 ...
- 【Apache运维基础(3)】虚拟主机配置说明
建议在主配置文件中增加一句 Include conf/vhosts/*.conf 然后就在vhosts目录下添加虚拟主机配置文件 在配置前打开NameVirtualHost *:80注释,注意此处要与 ...
- iOS开发-网易滚动导航栏
HACursor,是一个对横向ScrollView中的视图进行管理的UI控件.只要几行代码就可以集成类似于网易新闻对主题页面进行排序,删除操作的功能.主srollview参考iOS原生的UITable ...