数据劫持的用法
使用Object.defineProperty(params1,params2,params3)
- params1:需要劫持的对象
- params2:需要劫持的对象的具体的属性
- 劫持后需要写的get、set方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple HTML Template</title>
<!-- Add some style to the page -->
<style>
body {
background-color: lightblue;
}
h1 {
color: white;
text-align: center;
}
</style>
</head>
<body>
<h1>This is a simple HTML template</h1>
<p>Here's some text to fill the page.</p>
<h1>Vue 双向绑定的原理</h1>
<input type="text" id="myInput"></input>
<div> 显示值:<span id="mySpan"></span> </div>
<!-- Add some functionality to the page with JavaScript -->
<script>
// Vue 双向绑定的原理,丐版。即(数据劫持)
let obj = {};
// defineProperty() 需要三个参数:1.需要劫持的对象;2.劫持对象的具体属性;3.劫持后的get、set方法
Object.defineProperty(obj,'username',{
get(){
console.log('执行了get方法')
},
set(val){
console.log('执行了set方法',val)
document.getElementById("mySpan").innerText = val
}
})
document.getElementById("myInput").addEventListener("keyup",function(){
// event是当前的事件,即keyup方法
obj.username = event.target.value
})
</script>
</body>
</html>
数据响应式的原理:数据劫持 + 发布-订阅模式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple HTML Template</title>
<!-- Add some style to the page -->
<style>
body {
background-color: lightblue;
}
h1 {
color: white;
text-align: center;
}
</style>
</head>
<body>
<h1>This is a simple HTML template</h1>
<p>Here's some text to fill the page.</p>
<h1>Vue 响应式的原理</h1>
<div> 响应式的值 <span class="mySpan2"></span></div>
<!-- Add some functionality to the page with JavaScript -->
<script>
// Vue 相应式原理,丐版。本质是使用 发布-订阅模式 + 数据劫持 = 响应式
// 发布-订阅模式
class myWatcher{
constructor(){
this.message = {};
}
on(key,fn){
if(!this.message[key]){
this.message[key] = [];
}
this.message[key].push(fn);
}
off(key,fn){
if (!this.message[key]){
return;
}
if (!fn) {
this.message[key] = undefined;
}
this.message[key] = this.message[key].filter((item) => item !== fn);
}
emit(key,...args){
this.message[key].forEach(item=>{
item.apply(this,[...args]);
})
}
}
// 实现响应式 mydataObj:数据 mytag: 劫持数据具体的值 myWatcherKey:发布订阅模式用 myselector:选择器
const myw2 = new myWatcher();
function mvvmLow({mydataObj, mytag , myWatcherKey, myselector}){
let value = "";
el = document.querySelector(myselector);
Object.defineProperty(mydataObj,mytag,{
get(){
return value
},
set(val){
value = val;
// 使用发布订阅模式,当执行到set方法以后,发布消息,当页面接收到消息后,会改变值
myw2.emit(myWatcherKey,val);
}
})
myw2.on(myWatcherKey, function changeHandler(val){
el.innerText = val
});
}
var mydataObj = {};
let mytag = 'username';
let myWatcherKey = 'changeMethods';
let myselector = '.mySpan2';
// 执行这个的时候,会把'myw2.on'先给添加到'message'队列里面。
mvvmLow({mydataObj, mytag , myWatcherKey, myselector})
// 修改后,通过劫持,执行'myw2.emit',通过'myw2.emit'里面的逻辑,执行'myw2.on',注册进去的方法。
mydataObj.username = 22222
setTimeout(()=>{
mydataObj.username = 3333333
},2000)
</script>
</body>
</html>
Vue 代码层面的优化
- object.freeze() 不让数据双向绑定,性能提升。比如渲染10万条数据的时候,vue会给这10万条
数据加上get、set
。使用freeze以后,这10万条数据的get、set就不用加了
。提升了性能 - 为了优化css性能,可以尽量把css封装到
common.css
中,尽量不使用页面的<style scoped></style>
,影响css渲染性能。 - 大型项目页面缓存。使用
<keep-alive>
进行缓存,但是不能全部都缓存,如果有1000个页面的话,内存就卡爆炸了。推荐使用<keep-alive include>
,进行部分缓存。