我的应用程序中有一个颜色名称列表。
let colours = {
mango: '#e59c09',
midnight: '#1476a0'
};
我想扩展 ngStyle 指令,以便能够理解我的自定义颜色名称。我是通过decorating ngStyle 指令来完成的。但是,我在装饰者的编译功能上遇到了一场艰苦的战斗。我可以访问元素' ngStyle 属性,但它是一个字符串(可以理解)。 JSON.parse()
不起作用,因为它不一定是有效的JSON字符串,因为绑定一次等...
我只想介入,迭代所有样式键,如果它包含color
,我想检查值 - 如果它是上述自定义颜色之一,则替换为十六进制。< / p>
我似乎无法访问任何 ngStyle 内部函数,source code令人困惑和短暂;它似乎只是设置元素CSS - $ parse在哪里完成它的工作?例如,ng-style="{color: ctrl.textColor}"
时 - ngStyle 源代码中没有任何内容可以提取ctrl.textColour
的值。我在找错了地方吗?
无论如何,如何访问 ng-style 键值,以便我可以将自定义颜色更改为其十六进制代码?
这是我在装饰师中迄今为止所得到的:
$provide.decorator('ngStyleDirective', function($delegate) {
let directive = $delegate[0];
let link = directive.link;
directive.compile = function(element, attrs) {
// Expression here is a string property
let expression = attrs.ngStyle;
return function(scope, elem, attr) {
// How do I iterate over and update style values here?
// Run original function
link.apply(this, arguments);
}
}
return $delegate;
});
我尝试使用正则表达式来提取模式等并检查元素,但是,这似乎是向我解决问题的错误方法,因为我必须手动更新字符串并将其传递给基本链接函数。
如果有更好的方法来做我想做的事,请告诉我。
答案 0 :(得分:4)
无论如何,如何访问ng样式的键值,以便我可以将自定义颜色更改为其十六进制代码?
ngStyle 属性可以在编译函数中重写:
directive.compile = function(element, attrs) {
let expression = getExpressions(attrs.ngStyle);
attrs.ngStyle = expression;
return function(scope, elem, attr) {
// Run original function
link.apply(this, arguments);
}
}
JSON.parse(),这意味着 ng-style 属性需要用单引号分隔(尽管如果一个人真的想要,可以尝试逃避双引号...)
<p ng-style='{ "color": "#e59c09" }'>Hello {{name}}!</p>
<p ng-style='{ "padding": "20px 10px", "background-color": "#1476a0", "color": "#ddd" }'>It is dark here</p>
然后解析该字符串应该产生一个有效的对象,Object.keys()可以用来迭代键,检查单词 color 。如果密钥包含颜色,则Array.indexOf可用于检查 colors 数组中是否存在该值。如果它确实存在于数组中,则String.replace()可用于替换变量的值(即 colors 中的键)。
function getExpressions(str) {
var parsed = JSON.parse(str);
Object.keys(parsed).forEach(function(key) {
if (key.indexOf('color') > -1) {
if (Object.keys(colours).indexOf(parsed[key]) > -1) {
str = str.replace(parsed[key], colours[parsed[key]])
}
}
});
return str;
}
请参阅下面的示例中演示的内容。顺便说一下,我必须删除在函数 getExpressions()范围内声明的未使用的变量 colors ,因为它隐藏了对第3行上面定义的变量的访问权限。Here is an updated plunker。
let app = angular.module('plunker', []);
let colours = {
mango: '#e59c09',
midnight: '#1476a0'
};
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app.config(function($provide) {
// Extract colour values from the string
function getExpressions(str) {
var parsed = JSON.parse(str);
Object.keys(parsed).forEach(function(key) {
if (key.indexOf('color') > -1) {
if (Object.keys(colours).indexOf(parsed[key]) > -1) {
str = str.replace(parsed[key], colours[parsed[key]])
}
}
});
return str;
}
$provide.decorator('ngStyleDirective', function($delegate) {
let directive = $delegate[0];
let link = directive.link;
directive.compile = function(element, attrs) {
let expression = getExpressions(attrs.ngStyle);
attrs.ngStyle = expression;
return function(scope, elem, attr) {
// Run original function
link.apply(this, arguments);
}
}
return $delegate;
});
});
&#13;
div + div {
margin-top: 60px;
}
.comment {
font-family: courier;
font-size: 12px;
margin: 15px 0;
}
&#13;
<script src="https://code.angularjs.org/1.4.12/angular.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<div>
<p class="comment">--- with hex --</p>
<p ng-style='{ "color": "#e59c09" }'>Hello {{name}}!</p>
<p ng-style='{ "padding": "20px 10px", "background-color": "#1476a0", "color": "#ddd" }'>It is dark here</p>
</div>
<div>
<p class="comment">--- with custom colours --</p>
<p ng-style='{ "color": "mango" }'>Hello {{name}}!</p>
<p ng-style='{ "padding": "20px 10px", "background-color": "midnight", "color": "#ddd" }'>It is dark here</p>
</div>
</div>
&#13;
答案 1 :(得分:3)
实际上,如果你想使用parse - 你应该 - 你可以用它来解析表达式,替换属性,然后将属性转换回json。
你应该使用$ parse,因为如果你的代码看起来像是
// in the HTML
<p ng-style="{ padding: '20px 10px', 'background-color': myController.color, color: '#ddd' }">It is dark here</p>
// in the JS
myController.color = 'midnight';
然后解析JSON将无法正常工作。您应该使用$ parse解析表达式,并使用指令的作用域对象调用结果函数。
这就是为什么您的提供商应该是这样的:
$provide.decorator('ngStyleDirective', function($delegate, $parse) {
let directive = $delegate[0];
let link = directive.link;
directive.compile = function(element, attrs) {
return function(scope, elem, attrs) {
let ngStyleObject = $parse(attrs.ngStyle)(scope, {});
Object.keys(ngStyleObject).forEach(function(key) {
if (key.indexOf('color') > -1 && Object.keys(colours).indexOf(ngStyleObject[key]) > -1) {
ngStyleObject[key] = colours[ngStyleObject[key]];
}
});
attrs.ngStyle = JSON.stringify(ngStyleObject);
// Run original function
link.apply(this, arguments);
}
}
return $delegate;
});
您还可以复制原始的ngStyle函数(而不是调用其链接函数),因为添加您期望的行为非常简单:
$provide.decorator('ngStyleDirective', function($delegate) {
let directive = $delegate[0];
directive.compile = function(element, attrs) {
return function(scope, elem, attrs) {
// here, watch will do the $parse(attrs.ngStyle)(scope) and call the callback when values change
scope.$watch(attrs.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
if (oldStyles && (newStyles !== oldStyles)) {
oldStyles.forEach(function(val, style) { element.css(style, ''); });
}
if (newStyles) {
// instead of just setting the new styles, replace colors with their values
Object.keys(newStyles).forEach(function(key) {
if (key.indexOf('color') > -1 && Object.keys(colours).indexOf(newStyles[key]) > -1) {
newStyles[key] = colours[newStyles[key]];
}
});
element.css(newStyles);
}
}, true);
}
}
return $delegate;
});