【学习笔记70】数据劫持
2023-09-11 14:14:57 时间
一、 数据驱动视图
- 多次渲染页面,多的时候,比较麻烦和繁琐
const box = document.querySelector('.box')
const obj = {
name: 'QF666',
age: 18
}
box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
obj.age = 99;
box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
obj.name = 'QF999';
box.innerHTML = `名字: ${obj.name}; 年龄: ${obj.age}`;
console.log(obj);
二、数据劫持
- 将原始数据,劫持出一份一摸一样, 听起来有点像浅拷贝
- 劫持出来的数据, 默认是不可以修改的
语法: Object.defineProperty(那个对象, '对象的key', {配置项})
配置项:
1. value 访问这个值 之后, 得到结果
2. writable 决定当前这个属性能否被修改, 默认是 false
3. enumerable 决定当前这个属性能否被枚举, 决定当前这个属性能否被遍历到
4. getter 是一个函数, 是一个获取器, 当访问这个属性时, 会执行这个函数
getter不能和value、writable一起使用
5. setter 是一个函数, 是一个设置器, 当设置这个属性是, 会执行这个函数
1、初级版
const obj = {}
obj.name = 'QF666'
console.log(obj)
// Object.defineProperty(obj, str, {配置项})
Object.defineProperty(obj, 'age', {
// value: 'QF999',
// writable: true,
enumerable: true,
get() {
// console.log('你当前访问了这个age属性, 触发了get函数')
return 'qwerty'
},
set(val) {
console.log('你当前想要修改这个age属性, 修改的值是: ', val)
}
})
obj.age = 999
console.log(obj.age)
2、升级版
<div id="box"></div>
<script>
// 实现数据劫持
const box = document.querySelector('#box')
const obj = {
name: 'QF666',
age: 18
}
console.log('原始对象obj:', obj)
const res = {}
Object.defineProperty(res, 'name', {
get() {
return obj.name
},
set(val) {
// console.log('你想要修改这个属性的值, 新值为: ', val)
obj.name = val
box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
}
})
Object.defineProperty(res, 'age', {
get() {
return obj.age
},
set(val) {
// console.log('你想要修改这个属性的值, 新值为: ', val)
obj.age = val
box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
}
})
box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
res.age = 100;
</script>
三、封装数据劫持
<input type="text" name="" id="inp">
<div id="box"></div>
函数的封装 :
const box = document.querySelector('#box')
const obj = {
name: 'QF666',
age: 18
}
function observer(origin, callback) {
const target = {}
for (let k in origin) {
Object.defineProperty(target, k, {
get() {
return origin[k]
},
set(val) {
// console.log('你现在想要修改的key是' , k, '修改的值为', val)
origin[k] = val
callback(target)
}
})
}
callback(target)
return target
}
调用的
function fn(res) {
box.innerHTML = `名字: ${res.name}; 年龄: ${res.age}`
}
const app = observer(obj, fn)
document.querySelector('#inp').oninput = function (e) {
app.age = e.target.value
}
四、封装数据劫持+渲染
- 模拟一个其他人写的代码, 框架的源码
- 把需要渲染的代码, 都放到HTML 中, 然后由我这段代码帮助我们去渲染
<div id="app">
<h1> {{msg}} </h1>
<h1> {{ name }} </h1>
<h1> {{ age }} </h1>
<h1> {{ abc }} </h1>
</div>
封装的
<script>
function observer(options) {
// 1. 验证root有没有传递
if (options.root === undefined) {
// console.log('您没有传递root属性, 请重新传递')
// 手动返回一个错误
throw new Error('您没有传递root属性, 请重新传递')
}
// 2. 验证root能否正确获取到节点
const rootHtml = document.querySelector(options.root)
if (rootHtml == null) {
// 手动返回一个错误
throw new Error('您传递 root 的属性, 有问题, 请检查后重新传递')
}
// 3. 验证是否传递data
if (options.data == undefined) {
throw new Error('您没有传递 data 属性, 请重新传递')
}
// 4. 验证data是否为一个对象
if (options.data.constructor !== Object) {
throw new Error('您传递的 data 不是一个对象, 请重新传递')
}
// 5. 数据劫持
// 存储一份最初的html文本
const rootHtmlStr = rootHtml.innerHTML
// 这里存储最开始的具有{{}}的HTML文本,
// 如果不写, 第一次渲染完毕, HTML中就没有花括号, 第二次渲染正则没有办法正确匹配
const _data = {}
for (let k in options.data) {
Object.defineProperty(_data, k, {
get() {
return options.data[k]
},
set(val) {
options.data[k] = val
// 5.2 数据更新后, 重新渲染页面
randers(rootHtml, _data, rootHtmlStr)
}
})
}
// 5.1 首次执行, 渲染页面
randers(rootHtml, _data, rootHtmlStr)
// 6. 返回一个劫持后的数据
return _data
}
function randers(root, _data, str) {
// 准备一个正则
const reg = /{{ *(\w+) *}}/g
// 匹配到节点中所有的花括号, 存放在一个数组中
const res = str.match(reg)
// 遍历数组, 拿到每一个花括号
res.forEach(item => {
// 拿到花括号内的文本, 因为这是对象中的 key
const key = reg.exec(str)[1]
// 将原本花括号与内部文本, 全部替换为对象中实际的值
str = str.replace(/{{ *(\w+) *}}/, _data[key])
})
// 重新将修改完毕的字符串, 渲染到页面
root.innerHTML = str
}
</script>
调用的
<script>
// 我们后续使用, 就在这里
const app = observer({
root: '#app',
data: {
msg: '你好',
name: 'QF001',
age: 18,
abc: '醒醒, 别睡了, 说你呢, 还睡'
}
})
</script>
五、数据劫持升级
<div id="root"></div>
1、基本写法
const obj = {
name: 'QF001',
age: 18
}
const res = {}
Object.defineProperty(res, 'name', {
get() {
return obj.name;
},
set(val) {
obj.name = val;
}
})
obj.newName = 'QF999';
console.log(obj);
document.querySelector('#root').innerHTML = `name: ${obj.name}`;
2、升级版
语法: Object.defineProperties(到那个对象, {
属性1: 配置项,
属性2: 配置项
})
const obj = {
name: 'QF001',
age: 18
}
const res = {}
Object.defineProperties(res, {
name: {
get() {
return obj.name
},
set(val) {
obj.name = val
}
},
age: {
get() {
return obj.age
},
set(val) {
obj.age = val
}
}
})
obj.newName = 'QF999';
console.log(obj);
document.querySelector('#root').innerHTML = `name: ${obj.name}`;
3、升级版(plus)
const obj = {
name: 'QF001',
age: 18
}
const res = {};
// 升级版(plus)
for (let k in obj) {
// k === 'name' 2. k === age
console.log(k);
Object.defineProperties(res, {
// 对象内部直接写 k 会帮当成字符串, 所以可以写成 [k], 将他识别为变量
[k]: {
get() {
return obj[k];
},
set(val) {
obj[k] = val;
}
},
})
}
obj.newName = 'QF999';
console.log(obj);
document.querySelector('#root').innerHTML = `name: ${obj.name}`;
3、升级版(super plus), 自己劫持自己
const obj = {
name: 'QF001',
age: 18
}
for (let k in obj) {
Object.defineProperties(obj, {
['_' + k]: {
// 我在我这个对象内把所有属性复制一份, 放在自己这个对象内部
value: obj[k],
writable: true
},
[k]: {
get () {
return obj['_' + k]
},
set(val) {
obj['_' + k] = val
document.querySelector('#root').innerHTML = `name: ${obj.name}`
}
}
})
}
obj.newName = 'QF999'
console.log(obj)
document.querySelector('#root').innerHTML = `name: ${obj.name}`
相关文章
- NGUI 学习笔记实战之二——商城数据绑定(Ndata)
- 《ASP.NET MVC4 WEB编程》学习笔记------ViewBag、ViewData和TempData的使用和区别
- SPSS学习笔记之——Kaplan-Meier生存分析
- python的xml.dom学习笔记
- 机器学习笔记:常用数据集之scikit-learn在线下载开源数据集
- 机器学习笔记:常用数据集之scikit-learn内置玩具数据集
- 机器学习笔记 - 用于颜值评分的数据集和算法
- Opencv学习笔记 - 使用opencvsharp和knn进行手写识别训练和预测
- 机器学习笔记 - 基于Torch Hub的图像分割模型FCN
- 机器学习笔记 - 在IdenProf数据集上训练深度残差网络ResNet50
- 机器学习笔记 基于tensorflow2.0的手写数字识别,并导出pb模型供OpenCV的C++版本的DNN模块调用
- 机器学习笔记 - cifar10数据集下载及查看
- 【BSP视频教程】STM32H7视频教程第9期:STM32H7的GPIO专题,通过驱动源码,参考手册,数据手册应用笔记系统学习GPIO知识点(2022-03-06)
- Spring学习笔记之Design of DispatcherServlet
- SAP Analytics Cloud学习笔记(一):从CSV文件导入数据到Analytics Cloud里创建模型和Story
- AI公开课:19.05.29 浣军-百度大数据实验室主任《AutoDL 自动化深度学习建模的算法和应用》课堂笔记以及个人感悟
- Python零基础—网络爬虫入门,附学习路线+笔记+视频教程
- Swift学习笔记:类和结构
- OpenCV(C++接口)学习笔记1-图像读取、显示、保存
- HarmonyOS鸿蒙学习笔记(18)类似Android SharedPreferences保存数据
- MongoDB 学习笔记之 WriteConcern
- WPF学习笔记一 依赖属性及其数据绑定
- 深度学习笔记:利用预训练模型之特征提取训练小数据集上的图像分类器
- 深度学习笔记:在小数据集上从头训练卷积神经网络
- pytorch学习笔记(七):加载数据集