我看到的一个小'数组输入'聚合物元素的行为正在让我发挥最大作用。我创建了一个接受多个值的输入。在内部,值存储在“Array”属性中,并带有标记。这似乎按预期工作。
一旦添加了一个值(使用回车),它就会在数组框中装箱,然后重点关注新值的输入。我希望能够单击已添加的值并在输入中修改它们。现在,它拼接数组中的值,并将其值添加到输入中。
然而 - 当这样做时,单击(并巧合拼接)将使重复值'空白'。获取getValue()函数将返回一个完美的数组。单击“消隐”输出值将在输入中生成正确的值。
这是一个仍然表现出行为的元素的“淡化”版本。
<style>
:host {
display: block;
}
</style>
<template>
<array-items id="values">
<template is="dom-repeat" items="{{items}}">
<array-item style='padding:5px;margin-right:5px;background-color:lightblue;'>{{item}}</array-item>
</template>
<input id="input">
</array-items>
</template>
Polymer({
is: 'app-arraybox',
properties: {
// Items are the 'entries' inside the array-box
items: {
type: Object,
reflectToAttribute: true,
value: []
},
},
listeners: {
'input.keydown': '_inputKeys',
'input.blur': '_addValue',
'values.click': '_itemClick',
},
_inputKeys: function(event) {
var backspace = 8;
var enter = 13;
// If enter, then add a new value
if (event.keyCode == enter)
this._addValue();
// if backspace (and input is empty), then edit the last value
else if (event.keyCode == backspace) {
if (this.$.input.value.length < 1) {
event.preventDefault();
this._editValue();
}
}
},
// Handle clicking on an existing item
_itemClick: function(event) {
// Return if not clicking on an array-item -- this is bound
// to the container since items don't exist in the DOM yet
if (event.target.tagName != 'ARRAY-ITEM') return;
var child = event.target;
var input = this.$.input;
// Figure out index of clicked item by iterating through previousSiblings and checking them
var i = 0; while((child = child.previousSibling) != null) {
// only count ARRAY-ITEMS
if (child.tagName == 'ARRAY-ITEM') i++;
}
// Before continuing, if there's a value in the input already, add it to the arraybox
if (input.value.length > 0) this._addValue();
// Splice the value from 'this.items' and add the value to the input for editing
this.$.input.value = this.splice('items', i, 1);
// And finally, focus the input
this.$.input.focus();
},
_addValue: function() {
// Need the input, and value of the input
var input = this.$.input;
var value = input.value;
// Value must be at least a single character
if (value.length > 0) {
// Push the value to the array
this.push('items', value);
// Clear the text input
input.value = '';
} else {
// No 'meaningful' value was input
}
},
_editValue: function() {
var input = this.$.input;
if (this.items.length == 0)
return;
// Set the input to the last value in the array (pop also removes it from the array)
input.value = this.pop('items');
},
_updateIcon: function() {
// Check if icon is set and set <iron-icon> attribute if necessary
if (this.icon.length > 0)
this.$.icon.setAttribute('icon', this.icon);
// Else, remove the attribute on the <iron-icon>
else this.$.icon.removeAttribute('icon');
},
// Public 'getValue' for API/JavaScript interaction
getValue: function() {
// Return items array
return this.items;
},
});
请告诉我,我做的事情很愚蠢。 您可以在此处查看演示:app-arraybox demo
答案 0 :(得分:0)
Polymer依赖于object-identity来优化dom-repeat呈现,以应对不断变化的数据。当您的数据是具体的(简单的数字或字符串)时,数据没有标识(一个'foo'与任何其他'foo'相同)。如果您存储基于对象的数据({text: 'foo'}
),则每个对象都是唯一的。
此外,您通常不应该假设dom-node索引对应于数组索引,因为您可能希望将来对视图进行排序/过滤。
最后,Polymer提供了许多可用于处理您没有利用的集合和重复(以及各种其他任务)的功能。例如,您的itemClick
可以折叠为以下内容:
// Handle clicking on an existing item
_itemClick: function(event) {
// get the item reference from the event
var item = event.model.item;
// remove item from array
this.arrayDelete('items', item);
// return item text to edit mode
this.value = item.text;
this.$.input.focus();
},
这是一个实时版本的版本(仅限Chrome,为方便起见):
<!doctype html>
<head>
<meta name="description" content="color-thief with Polymer">
<meta charset="utf-8">
<base href="http://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link rel="import" href="iron-icon/iron-icon.html">
<link rel="import" href="iron-icons/iron-icons.html">
<style>
body {
font-family: sans-serif;
background-color: #999;
}
</style>
</head>
<body>
<app-arraybox icon="menu"></app-arraybox>
<!--
[ APP-ARRAYBOX | BY JEREMY SCHROEDER | ... ]
Multi-value input boxes that hold values as an array.
-->
<!-- 'dom-module' is a Polymer element that registers arbitrary content by an `id`-->
<dom-module id="app-arraybox">
<!-- The style contained is relative to the element itself and will not style
anything outside. To style the element itself, use the ':host' specifier -->
<style>
:host {
display: block;
cursor: text;
}
:host.raised {
border: 1px solid lightgray;
border-bottom: 4px solid lightgray;
border-right: 4px solid lightgray;
padding-left: 6px;
border-radius: 3px;
}
iron-icon {
display: none;
}
iron-icon[icon] {
display: inline-block;
top: 8px;
margin-right: 12px;
margin-left: 6px;
}
input {
flex: 1 1;
height: 28px;
padding: 6px;
border: none;
outline: none;
padding-left: 12px;
font-size: 100%;
}
array-item {
flex: none;
padding: 3px;
padding-right: 12px;
padding-left: 12px;
margin-bottom: 4px;
margin-right: 6px;
background-color: whitesmoke;
top: 7px;
position: relative;
height: 21px;
border-radius: 3px;
cursor: pointer;
}
array-items {
max-width: 100%;
flex: none;
display: flex;
flex-wrap: wrap;
}
</style>
<!-- The template contains the markup of the element itself. <content></content> can be used to pass along
any 'inner text' that the user specifies. There are also a slew of 'helpers' such as template repeating,
data binding, and event registration that can be taken advantage of here. -->
<template>
<array-items id="values">
<iron-icon id="icon" icon$="{{icon}}"></iron-icon>
<template is="dom-repeat" items="{{items}}">
<array-item on-click="_itemClick">{{item.text}}</array-item>
</template>
<input id="input" value="{{value::input}}" on-blur='_commitValue' on-keydown="_inputKeys">
</array-items>
</template>
<!-- The script contains is called upon registration. Though it typically includes a call to Polymer(...), it can also
include other code that can be used to manage the element and its features. -->
<script>
Polymer({
// Required -- tells Polymer which element is being registered. If there is a dom-module
// registered with the same value for `id`, Polymer will look in that dom-module for
// templates and style-sheets.
is: 'app-arraybox',
// Properties registered here can be accessed via 'this' at any time.
properties: {
// Items are the 'entries' inside the array-box
items: {
type: Object,
value: function() {
return [];
}
},
// Icon is an iron-icon that can be shown at the beginning of the arraybox (optional)
icon: {
type: String,
reflectToAttribute: true
},
raised: {
type: Boolean,
reflectToAttribute: true,
value: false,
observer: '_raise'
},
value: {
value: ''
}
},
// Register listeners -- these will execute functions when the specified event is fired
listeners: {
'click': '_focusInput'
},
_raise: function() {
this.toggleClass('raised', this.raised);
},
_focusInput: function(event) {
if (event.target.tagName == 'APP-ARRAYBOX')
this.$.input.focus();
},
// Handle 'keyup' for the input
_inputKeys: function(event) {
var backspace = 8;
var enter = 13;
// If enter, then add a new value
if (event.keyCode == enter) {
this._commitValue();
} else
// if backspace, then edit the last value
if (event.keyCode == backspace) {
if (this.$.input.value.length <= 0) {
event.preventDefault();
this._editValue();
}
}
},
// Handle clicking on an existing item
_itemClick: function(event) {
// get the item reference from the event
var item = event.model.item;
// remove item from array
this.arrayDelete('items', item);
// return item text to edit mode
this.value = item.text;
this.$.input.focus();
},
_commitValue: function() {
// Value must be at least a single character
if (this.value.length > 0) {
console.log('Adding ' + this.value);
// Push the value to the array
this.addValue(this.value);
// Clear the text input
this.value = '';
} else {
// No 'meaningful' value was input
}
},
_editValue: function() {
// Value must none, otherwise it's a regular 'backspace', in which case we just return without
// doing anything.
if (this.items.length > 0) {
// Set the input to the last value in the array (pop also removes it from the array)
this.value = this.pop('items');
}
},
// Public 'addValue' for API/JavaScript interaction
addValue: function(value) {
// Push new item to the items array
this.push('items', {text: value});
},
// Public 'getValue' for API/JavaScript interaction
getValue: function() {
// Return items array
return this.items;
},
setValue: function(array) {
this.items = array;
}
});
</script>
</dom-module>
</body>