数据响应式是vue的特性之一,在面试过程中也会常常被问起响应式原理,现在就让我们深入了解一下vue2.0中如何实现响应式,

Object.defineProperty是什么?
let object1={
property1:0 } //例如 Object.defineProperty(object1, 'property1', {
value: 42, writable: false, //是否可写 configurable: false, //是否可删除 enumerable: false, //是否可枚举(遍历) }); //get set配置项 Object.defineProperty(object1, 'property1', {
get() {
//get方法在进行获取的时候触发 return property1 }, set(newVal) {
//get方法在进行设置的时候触发,主要在此实现数据劫持 property1 = newVal } }); //我这边常用一种复数形式Object.defineProperties Object.defineProperties(object1, {
property1: {
get() {
//get方法在进行获取的时候触发 return property1 }, set(newVal) {
//get方法在进行设置的时候触发,主要在此实现数据劫持 property1 = newVal } } })
使用上述的内容实现Vue2.0中的双向绑定
实现出来的效果

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> .btnGroup > button.active{
background-color: orange; color: #fff; }
style>
head> <body> <div id="computed"> <div class="result">0
div> <div class="inputGroup"> <input type="number" class="ipt1" value="0" /> <br/> <input type="number" class="ipt2" value="0" />
div> <div class="btnGroup"> <button data-field="add" class="active">+
button> <button data-field="sub">-
button> <button data-field="mul">*
button> <button data-field="div">/
button>
div>
div>
<script src="./js/index.js">
script>
body>
html>
js部分
class Arithmetic {
//定义算法类 add(a, b) {
return a + b } sub(a, b) {
return a - b } mul(a, b) {
return a * b } div(a, b) {
return a / b } } class Computed extends Arithmetic {
constructor() {
super(); this.result = document.getElementsByClassName('result')[0]; //获取结果dom this.ipt1 = document.getElementsByClassName('ipt1')[0]; //获取输入框 this.ipt2 = document.getElementsByClassName('ipt2')[0]; this.btnGroup = document.getElementsByClassName('btnGroup')[0]; this.btnItems = this.btnGroup.getElementsByTagName('button'); this.data = this.defineData(); this.btnIndex = 0; //记录选中btn索引 } // 1.进行初始化 init() {
this.bindEvent(); } // 2.绑定事件 bindEvent() {
this.btnGroup.addEventListener('click', this.onFieldBtnClick.bind(this), false) this.ipt1.addEventListener('input', this.onNumberIpt.bind(this), false) this.ipt2.addEventListener('input', this.onNumberIpt.bind(this), false) } // 6.使用Object.defineProperty进行数据劫持 defineData() {
let _obj = {
}, field = 'add', //保存计算方法字段 fNumber = 0, //inp1的value sNumber = 0; //inp2的value let that = this; // 进行数据劫持 Object.defineProperties(_obj, {
fNumber: {
get() {
return fNumber }, set(newVal) {
fNumber = newVal // 重点:在fNumber改变之后计算结果,此处vue使用的是Dom diff算法 that.computedResult(fNumber, sNumber, field); } }, sNumber: {
get() {
return sNumber }, set(newVal) {
sNumber = newVal that.computedResult(fNumber, sNumber, field); } }, field: {
get() {
return field }, set(newVal) {
field = newVal that.computedResult(fNumber, sNumber, field); } } }) return _obj } // 3.btn点击事件 onFieldBtnClick(ev) {
let e = ev || window.event, tar = e.target || e.srcElement, tarName = tar.tagName.toLowerCase(); tarName === 'button' && this.update(tar); } // 4.btn进行选项卡切换并更改field update(target) {
this.btnItems[this.btnIndex].className = ''; this.btnIndex = [].indexOf.call(this.btnItems, target); target.className += ' active'; this.data.field = target.getAttribute('data-field'); } // 5.ipt改变(input)事件 onNumberIpt(ev) {
let e = ev || window.event, tar = e.target || e.srcElement, className = tar.className, val = Number(tar.value.replace(/\s+/g, '')) || 0; //去除input的空格 switch (className) {
case 'ipt1': // 改变fNumber触发set()将重新计算结果 this.data.fNumber = val; break; case 'ipt2': // 改变sNumber触发set()将重新计算结果 this.data.sNumber = val; break; default: break; } } // 7.使用继承算法类的方法进行结果计算 computedResult(fNumber, sNumber, field) {
this.result.innerHTML = this[field](fNumber, sNumber) } } new Computed().init();
往期精彩文章
- 一篇文章带你揭秘现代浏览器原理
- 带你深入理解什么叫js闭包
- 前端性能优化之rel=“prefetch“预/懒加载功能
- 前端唤起相机的方法H5+JS
- docker下YApi部署教程-支持swagger数据导入
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204874.html原文链接:https://javaforall.net
