vue.js学习09之vue2.x实现vue1.x中默认的过滤器
最近在学习vue.js,新版本是2.3.0了。在学习过滤器知识时,网上的一些例子是基于vue1.X官方提供的默认的过滤器,但是在vue2.x中全部取消了,都需要自己实现了。但是在vue.js的1.x版本中可以看到默认的过滤器的实现源码。我们可以把想过过滤器的源码复制出来,结合vue2.x过滤器的要求,做一些简单处理就可以使用了。在vue2.x中仍然可以在文本中使用过滤器,比如{{message |
·
最近在学习vue.js,新版本是2.3.0了。在学习过滤器知识时,网上的一些例子是基于vue1.X官方提供的默认的过滤器,但是在vue2.x中全部取消了,都需要自己实现了。但是在vue.js的1.x版本中可以看到默认的过滤器的实现源码。我们可以把想过过滤器的源码复制出来,结合vue2.x过滤器的要求,做一些简单处理就可以使用了。在vue2.x中仍然可以在文本中使用过滤器,比如{{message | capitalize }} ,但是在v-for中就不能直接使用orderby 等过滤器了。
filter.html做测试,vue.js是2.3.0版本的
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="bootstrap-3.3.7/dist/css/bootstrap.min.css">
<script src="vue.js"></script>
<script src="filter.js"></script>
</head>
<body>
<div id="app">
<table class='table table-bordered'>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Sex</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr v-for="person in peopleOderBy ">
<td>{{ person.name | capitalize }}</td>
<td>{{ person.age }}</td>
<td>{{ person.sex }}</td>
<td>{{ person.salary | currency('¥','0') }}</td>
</tr>
</tbody>
</table>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
people: [{
name: 'jack',
age: 30,
sex: 'male',
salary: '8000'
}, {
name: 'bill',
age: 26,
sex: 'male',
salary: '7000'
}, {
name: 'Tracy',
age: 22,
sex: 'female',
salary: '4500'
}, {
name: 'chris',
age: 36,
sex: 'male',
salary: '9000'
}]
},
computed: {
peopleLimitBy: function() {
return limitBy(this.people, 2, 1);
},
peopleFilterBy: function() {
return filterBy(this.people, 'r', 'in', 'name', 'sex');
},
peopleOderBy: function() {
return orderBy(this.people, 'age', 1);
}
}
})
</script>
<style>
body {
margin: 0 auto;
margin-left: 30%;
margin-right: 30%;
margin-top: 10px;
}
</style>
</html>
其中filter.js就是从vue.js 1.x版本中复制出来的一些过滤器的代码
/**
* 字符串的第一个字母大写
*/
Vue.filter('capitalize', function(value) {
if (!value && value !== 0) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
/**
* 将字符串全部转为大写字母
*/
Vue.filter('uppercase', function(value) {
return value || value === 0 ? value.toString().toUpperCase() : '';
});
/**
* 将字符串全部转为小写字母
*/
Vue.filter('uppercase', function(value) {
return value || value === 0 ? value.toString().toLowerCase() : '';
});
/**
* 12345 => $12,345.00
*
* @param {String} sign
* @param {Number} decimals Decimal places
*/
Vue.filter('currency', function(value, _currency, decimals) {
value = parseFloat(value);
if (!isFinite(value) || !value && value !== 0) return '';
_currency = _currency != null ? _currency : '$';
decimals = decimals != null ? decimals : 2;
var stringified = Math.abs(value).toFixed(decimals);
var _int = decimals ? stringified.slice(0, -1 - decimals) : stringified;
var i = _int.length % 3;
var head = i > 0 ? _int.slice(0, i) + (_int.length > 3 ? ',' : '') : '';
var _float = decimals ? stringified.slice(-1 - decimals) : '';
var sign = value < 0 ? '-' : '';
var digitsRE = /(\d{3})(?=\d)/g;
return sign + _currency + head + _int.slice(i).replace(digitsRE, '$1,') + _float;
});
/**
* 'item' => 'items'
*
* @params
* an array of strings corresponding to
* the single, double, triple ... forms of the word to
* be pluralized. When the number to be pluralized
* exceeds the length of the args, it will use the last
* entry in the array.
*
* e.g. ['single', 'double', 'triple', 'multiple']
*/
Vue.filter('pluralize', function(value) {
var args = toArray(arguments, 1);
return args.length > 1 ? args[value % 10 - 1] || args[args.length - 1] : args[0] + (value === 1 ? '' : 's');
});
/**
* Limit filter for arrays
*
* @param {Number} n
* @param {Number} offset (Decimal expected)
*/
function limitBy(arr, n, offset) {
offset = offset ? parseInt(offset, 10) : 0;
n = toNumber(n);
return typeof n === 'number' ? arr.slice(offset, offset + n) : arr;
}
/**
* Filter filter for arrays
*
* @param {String} search
* @param {String} [delimiter]
* @param {String} ...dataKeys
*/
function filterBy(arr, search, delimiter) {
arr = convertArray(arr);
if (search == null) {
return arr;
}
if (typeof search === 'function') {
return arr.filter(search);
}
// cast to lowercase string
search = ('' + search).toLowerCase();
// allow optional `in` delimiter
// because why not
var n = delimiter === 'in' ? 3 : 2;
// extract and flatten keys
var keys = Array.prototype.concat.apply([], toArray(arguments, n));
var res = [];
var item, key, val, j;
for (var i = 0, l = arr.length; i < l; i++) {
item = arr[i];
val = item && item.$value || item;
j = keys.length;
if (j) {
while (j--) {
key = keys[j];
if (key === '$key' && contains(item.$key, search) || contains(getPath(val, key), search)) {
res.push(item);
break;
}
}
} else if (contains(item, search)) {
res.push(item);
}
}
return res;
};
/**
* 排序
*/
function orderBy(arr) {
var comparator = null;
var sortKeys = undefined;
arr = convertArray(arr);
// determine order (last argument)
var args = toArray(arguments, 1);
var order = args[args.length - 1];
if (typeof order === 'number') {
order = order < 0 ? -1 : 1;
args = args.length > 1 ? args.slice(0, -1) : args;
} else {
order = 1;
}
// determine sortKeys & comparator
var firstArg = args[0];
if (!firstArg) {
return arr;
} else if (typeof firstArg === 'function') {
// custom comparator
comparator = function(a, b) {
return firstArg(a, b) * order;
};
} else {
// string keys. flatten first
sortKeys = Array.prototype.concat.apply([], args);
comparator = function(a, b, i) {
i = i || 0;
return i >= sortKeys.length - 1 ? baseCompare(a, b, i) : baseCompare(a, b, i) || comparator(a, b, i + 1);
};
}
function baseCompare(a, b, sortKeyIndex) {
var sortKey = sortKeys[sortKeyIndex];
if (sortKey) {
if (sortKey !== '$key') {
if (isObject(a) && '$value' in a) a = a.$value;
if (isObject(b) && '$value' in b) b = b.$value;
}
a = isObject(a) ? getPath(a, sortKey) : a;
b = isObject(b) ? getPath(b, sortKey) : b;
}
return a === b ? 0 : a > b ? order : -order;
}
// sort on a copy to avoid mutating original array
return arr.slice().sort(comparator);
};
/**
* Convert an Array-like object to a real Array.
*/
function toArray(list, start) {
start = start || 0;
var i = list.length - start;
var ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret
}
function convertArray(value) {
if (Array.isArray(value)) {
return value;
} else if (isPlainObject(value)) {
// convert plain object to array.
var keys = Object.keys(value);
var i = keys.length;
var res = new Array(i);
var key;
while (i--) {
key = keys[i];
res[i] = {
$key: key,
$value: value[key]
};
}
return res;
} else {
if (typeof value === 'number' && !isNaN(value)) {
value = range(value);
}
return value || [];
}
}
/**
* String contain helper
*
* @param {*} val
* @param {String} search
*/
function contains(val, search) {
var i;
if (isPlainObject(val)) {
var keys = Object.keys(val);
i = keys.length;
while (i--) {
if (contains(val[keys[i]], search)) {
return true;
}
}
} else if (Array.isArray(val)) {
i = val.length;
while (i--) {
if (contains(val[i], search)) {
return true;
}
}
} else if (val != null) {
return val.toString().toLowerCase().indexOf(search) > -1;
}
}
/**
* Quick object check - this is primarily used to tell
* Objects from primitive values when we know the value
* is a JSON-compliant type.
*/
function isObject(obj) {
return obj !== null && typeof obj === 'object'
}
function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
* Check and convert possible numeric strings to numbers
* before setting back to data
*
* @param {*} value
* @return {*|Number}
*/
function toNumber(value) {
if (typeof value !== 'string') {
return value;
} else {
var parsed = Number(value);
return isNaN(parsed) ? value : parsed;
}
}
function getPath(obj, path) {
return parseExpression(path).get(obj);
}
/**
* Parse an expression into re-written getter/setters.
*
* @param {String} exp
* @param {Boolean} needSet
* @return {Function}
*/
var expressionCache = new Cache(1000);
var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/;
var booleanLiteralRE = /^(?:true|false)$/;
function parseExpression(exp, needSet) {
exp = exp.trim();
// try cache
var hit = expressionCache.get(exp);
if (hit) {
if (needSet && !hit.set) {
hit.set = compileSetter(hit.exp);
}
return hit;
}
var res = { exp: exp };
res.get = isSimplePath(exp) && exp.indexOf('[') < 0
// optimized super simple getter
?
makeGetterFn('scope.' + exp)
// dynamic getter
:
compileGetter(exp);
if (needSet) {
res.set = compileSetter(exp);
}
expressionCache.put(exp, res);
return res;
}
function Cache(limit) {
this.size = 0;
this.limit = limit;
this.head = this.tail = undefined;
this._keymap = Object.create(null);
}
var p = Cache.prototype;
/**
* Put <value> into the cache associated with <key>.
* Returns the entry which was removed to make room for
* the new entry. Otherwise undefined is returned.
* (i.e. if there was enough room already).
*
* @param {String} key
* @param {*} value
* @return {Entry|undefined}
*/
p.put = function(key, value) {
var removed;
if (this.size === this.limit) {
removed = this.shift();
}
var entry = this.get(key, true);
if (!entry) {
entry = {
key: key
};
this._keymap[key] = entry;
if (this.tail) {
this.tail.newer = entry;
entry.older = this.tail;
} else {
this.head = entry;
}
this.tail = entry;
this.size++;
}
entry.value = value;
return removed;
};
/**
* Purge the least recently used (oldest) entry from the
* cache. Returns the removed entry or undefined if the
* cache was empty.
*/
p.shift = function() {
var entry = this.head;
if (entry) {
this.head = this.head.newer;
this.head.older = undefined;
entry.newer = entry.older = undefined;
this._keymap[entry.key] = undefined;
this.size--;
}
return entry;
};
/**
* Get and register recent use of <key>. Returns the value
* associated with <key> or undefined if not in cache.
*
* @param {String} key
* @param {Boolean} returnEntry
* @return {Entry|*}
*/
p.get = function(key, returnEntry) {
var entry = this._keymap[key];
if (entry === undefined) return;
if (entry === this.tail) {
return returnEntry ? entry : entry.value;
}
// HEAD--------------TAIL
// <.older .newer>
// <--- add direction --
// A B C <D> E
if (entry.newer) {
if (entry === this.head) {
this.head = entry.newer;
}
entry.newer.older = entry.older; // C <-- E.
}
if (entry.older) {
entry.older.newer = entry.newer; // C. --> E
}
entry.newer = undefined; // D --x
entry.older = this.tail; // D. --> E
if (this.tail) {
this.tail.newer = entry; // E. <-- D
}
this.tail = entry;
return returnEntry ? entry : entry.value;
};
function isSimplePath(exp) {
return pathTestRE.test(exp) &&
// don't treat true/false as paths
!booleanLiteralRE.test(exp) &&
// Math constants e.g. Math.PI, Math.E etc.
exp.slice(0, 5) !== 'Math.';
}
function makeGetterFn(body) {
try {
/* eslint-disable no-new-func */
return new Function('scope', 'return ' + body + ';');
/* eslint-enable no-new-func */
} catch (e) {
'development' !== 'production' && warn('Invalid expression. ' + 'Generated function body: ' + body);
}
}
更多推荐
已为社区贡献3条内容
所有评论(0)