目前阶段,国内前端’基础框架 - vue’异常火热,不论是面试、工作运用都不可或缺,其便利之处就在于页面内容随数据变化而自动变化,在此记录使用defineProperty自动渲染的示例,并根据此例来加深对于自动渲染的的理解
defineProperty & defineProperties
作用: 直接在一个对象上定义一个(多个)新属性,或者修改一个(多个)对象的现有属性,并返回此对象
value: 绑定属性的数值
writable: 是否可重写数据
enumerable: 是否可枚举对象键名(是否可被Object.keys())
configurable: 对象属性是否可被删除
defineProperty与defineProperties的区别就在于各自绑定属性的数量,defineProperties可同时绑定多个,而defineProperty绑定一个属性:
function Test1() {
let obj = {},
name = ''
Object.defineProperty(obj, 'name', {
// enumerable: false,
// value: '伽罗',
// writable: false,
// configurable: false,
get() {
console.log('Test1: get new value(name): ' + name);
return name;
},
set(newVal) {
name = newVal;
console.log('Test1: set new value(name): ' + newVal);
}
})
return obj;
}
let t1 = new Test1()
t1.name = '张三'
function Test2() {
let obj = {},
name= '',
age = 18
Object.defineProperties(obj, {
name: {
get() {
console.log('Test2: get new value(name): ' + name);
return name;
},
set(newVal) {
name = newVal;
console.log('Test2: set new value(name): ' + newVal);
}
},
age: {
get() {
console.log('Test2: get new value(age): ' + age);
return age;
},
set(newVal) {
age = newVal;
console.log('Test2: set new value(age): ' + newVal);
}
}
})
return obj;
}
let t2 = new Test2()
t2.name = '张三'
t2.age = 20
通过上述两个小例子可以看出各自的运用方式,但需要注意的一点是:
getter、setter和value、writable属性不能同时存在,否则会显示 Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
想要查看详细信息可点击Object.defineProperty前往查看详情
后续是借助此功能编写的计算器功能,能够直接复制到本地运行查看效果
html内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算器</title>
<style>
body{
padding: 10px 20px;
}
input{
height: 30px;
outline: none;
display: block;
border: none;
border-radius: 4px;
box-shadow: 0 0 5px #cccccc;
margin-bottom: 10px;
padding-left: 5px;
}
button{
width: 30px;
height: 30px;
border-radius: 4px;
text-align: center;
cursor: pointer;
margin-right: 10px;
outline: none;
border: none;
box-shadow: 0 0 5px #cccccc;
user-select: none;
}
.result{
color: #999999;
font-size: 13px;
}
.result .num{
color: #333333;
font-size: 14px;
}
.btn-group .active{
background: rgb(247, 163, 67);
color: #ffffff;
}
</style>
</head>
<body>
<div class="calculator">
<p class="result">运算结果: <span class="num">0</span></p>
<input class="f-input" type="number" value="0" />
<input class="s-input" type="number" value="0" />
<div class="btn-group">
<button data-field="plus" class="active">+</button>
<button data-field="minus">-</button>
<button data-field="mul">*</button>
<button data-field="div">/</button>
</div>
</div>
<script src="./js/calculator.js"></script>
</body>
</html>
calculator.js:
// 算数运算类
class Compute {
plus(a, b) {
return a + b;
}
minus(a, b) {
return a - b;
}
mul(a, b) {
return a * b;
}
div(a, b) {
if(a % b === 0) {
return a / b;
}else if(a / b) {
return (a / b).toFixed(3) || 0;
}else {
return 0;
}
}
}
// 计算器类
class Calculator extends Compute {
constructor(doc) {
super();
const oCal = doc.querySelector('.calculator');
this.fInput = oCal.querySelector('.f-input');
this.sInput = oCal.querySelector('.s-input');
this.oBtnGroup = oCal.querySelector('.btn-group');
this.oBtnItems = this.oBtnGroup.querySelectorAll('button');
this.oResult = oCal.querySelector('.result .num');
this.data = this.defineData();
this.btnIdx = 0;
}
// 初始化
init() {
this.bindEvent();
}
// 绑定、监听元素
bindEvent() {
this.oBtnGroup.addEventListener('click', this.onFieldBtnClick.bind(this), false);
this.fInput.addEventListener('input', this.onNumberInput.bind(this), false);
this.sInput.addEventListener('input', this.onNumberInput.bind(this), false);
}
// 点击计算按钮
onFieldBtnClick(ev) {
const e = ev || window.event,
tar = e.target || e.srcElement,
tagName = tar.tagName.toLowerCase();
tagName === 'button' && this.fieldUpdate(tar);
}
// 计算文字变化
onNumberInput(ev) {
const e = ev || window.event,
tar = e.target || e.srcElement,
className = tar.className,
val = Number(tar.value.replace(/\s+/g, '')) || 0;
switch(className) {
case 'f-input':
this.data.fNumber = val;
break;
case 's-input':
this.data.sNumber = val;
break;
default:
break;
}
}
// 监听 - 切换运算符选中
fieldUpdate(target) {
this.oBtnItems[this.btnIdx].className = '';
this.btnIdx = [].indexOf.call(this.oBtnItems, target);
target.className += ' active';
this.data.field = target.getAttribute('data-field');
}
// 渲染计算结果
computeResult(fNumber, sNumber, field) {
this.oResult.innerText = this[field](fNumber, sNumber);
}
// 数据监听
defineData() {
let _obj = {},
fNumber = 0,
sNumber = 0,
field = 'plus';
const _self = this;
Object.defineProperties(_obj, {
fNumber: {
get() {
return fNumber;
},
set(newVal) {
fNumber = newVal;
_self.computeResult(fNumber, sNumber, field);
}
},
sNumber: {
get() {
return sNumber;
},
set(newVal) {
sNumber = newVal;
_self.computeResult(fNumber, sNumber, field);
}
},
field: {
get() {
return field;
},
set(newVal) {
field = newVal;
_self.computeResult(fNumber, sNumber, field);
}
}
})
return _obj;
}
}
new Calculator(document).init();
演示效果:
感谢大家读阅,若有何想法踊跃提问,一起思索
希望能帮到你,拜拜~