-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 74 题: 使用 JavaScript Proxy 实现简单的数据绑定 #123
Comments
|
<div id="app">
<input type="text" id="input">
<div>
TODO:
<span id="text"></span>
</div>
<div id="btn">Add To Todo List</div>
<ul id="list"></ul>
</div> const input = document.getElementById('input')
const text = document.getElementById('text')
const list = document.getElementById('list')
const btn = document.getElementById('btn')
let render
const inputObj = new Proxy({}, {
get (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
if (key === 'text') {
input.value = value
text.innerHTML = value
}
return Reflect.set(target, key, value, receiver)
}
})
class Render {
constructor (arr) {
this.arr = arr
}
init () {
const fragment = document.createDocumentFragment()
for (let i = 0; i < this.arr.length; i++) {
const li = document.createElement('li')
li.textContent = this.arr[i]
fragment.appendChild(li)
}
list.appendChild(fragment)
}
addList (val) {
const li = document.createElement('li')
li.textContent = val
list.appendChild(li)
}
}
const todoList = new Proxy([], {
get (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
if (key !== 'length') {
render.addList(value)
}
return Reflect.set(target, key, value, receiver)
}
})
window.onload = () => {
render = new Render([])
render.init()
}
input.addEventListener('keyup', e => {
inputObj.text = e.target.value
})
btn.addEventListener('click', () => {
todoList.push(inputObj.text)
inputObj.text = ''
}) |
<b id="count"></b>
<button onclick="increase()">+</button>
<button onclick="decrease()">-</button> const data = { count: 0 };
const proxy = new Proxy(data, {
get(target, property) {
return target[property];
},
set(target, property, value) {
target[property] = value;
render(value);
}
});
render(proxy.count);
function render(value) {
document.getElementById('count').innerHTML = value;
}
function increase() {
proxy.count += 1;
}
function decrease() {
proxy.count -= 1;
} |
|
利用Proxy实现一个简化版的MVVM <!-- html部分 -->
<div id="foo"></div>
<input type="text" name="" id="bar"/> // js部分
class Watcher{
constructor(cb){
this.cb = cb;
}
update(){
this.cb()
}
}
class Dep{
constructor(){
this.subs = [];
}
publish(){
this.subs.forEach((item)=>{
item.update && item.update();
})
}
}
class MVVM{
constructor(data){
let that = this;
this.dep = new Dep();
this.data = new Proxy(data,{
get(obj, key, prox){
that.dep.target && that.dep.subs.push(that.dep.target);
return obj[key]
},
set(obj, key, value, prox){
obj[key] = value;
that.dep.publish();
return true;
}
})
this.compile();
}
compile(){
let divWatcher = new Watcher(()=>{
this.compileUtils().div();
})
this.dep.target = divWatcher;
this.compileUtils().div();
this.dep.target = null;
let inputWatcher = new Watcher(()=>{
this.compileUtils().input();
})
this.dep.target = inputWatcher;
this.compileUtils().input();
this.compileUtils().addListener();
this.dep.target = null;
}
compileUtils(){
let that = this;
return {
div(){
document.getElementById('foo').innerHTML = that.data.foo;
},
input(){
document.getElementById('bar').value = that.data.bar;
},
addListener(){
document.getElementById('bar').addEventListener('input', function(){
that.data.bar = this.value;
})
}
}
}
}
let mvvm = new MVVM({foo: 'foo233', bar: 'bar233'}) 通过 |
set 方法必须返回 true 或者 false 你这样写是有问题的 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set |
|
可打开f12修改 |
监听dom的value变化 去更新 obj 普通简易版本: 名字:<input type="text" id="name"><br/>
你的名字: <p id="pName"></p>
<script type="text/javascript">
var obj = {
name: ''
}
Object.defineProperty(obj, 'name', {
set: function(value) {
document.getElementById('name').value = value
document.getElementById('pName').innerHTML = value
}
})
document.getElementById('name').addEventListener('input', function(e){
obj.name = e.target.value
})
</script>
proxy版本 好像没啥特殊的: 名字:<input type="text" id="name"><br/>
你的名字: <p id="pName"></p>
<script type="text/javascript">
// Proxy
var obj = {
name: ''
}
var proxyObj = new Proxy(obj, {
get: function(target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function(target, key, value, receiver) {
if (key === 'name') {
document.getElementById('name').value = value
document.getElementById('pName').innerHTML = value
}
return Reflect.set(target, key, value, receiver)
}
})
document.getElementById('name').addEventListener('input', function(e){
proxyObj.name = e.target.value
})
</script>
|
<body>
<div id="root">
<input type="text" v-model="title">
<input type="text" v-model="title">
<div v-bind="title"> </div>
</div>
<script>
'user strict'
function View() {
// 设置代理拦截
let proxy = new Proxy({}, {
get(obj, property) { },
set(obj, property, value) {
document.querySelectorAll(`[v-model='${property}'],[v-bind='${property}']`)
.forEach(el => el.innerHTML = el.value = value)
}
})
// 初始化 绑定元素
this.run = function () {
const elems = document.querySelectorAll("[v-model]");
elems.forEach(el => {
el.addEventListener('keyup', event => {
proxy[event.target.getAttribute('v-model')] = event.target.value;
})
})
}
}
let view = new View();
view.run();
</script>
</body> |
<input id="inp" type="text" oninput="handleChange()">
<div id="app"></div>
<script>
let inp = document.getElementById('inp')
let app = document.getElementById('app')
let obj = {
defaultValue: 'hello world'
}
let proxy = new Proxy(obj, {
get: function(obj, key) {
console.log('get')
return obj[key]
},
set(obj, key, value) {
obj.defaultValue = value
notify()
}
})
app.innerHTML = proxy.defaultValue
inp.value = proxy.defaultValue
function notify() {
app.innerHTML = proxy.defaultValue
}
function handleChange() {
proxy.defaultValue = inp.value
}
</script> |
model.value = value; 这一行代码是不是不需要写 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<span></span>
<br>
<input type="text" oninput="input(event)">
<script>
let spanEl = document.querySelector('span')
let inputEl = document.querySelector('input')
let data = {
val: null
}
let proxy = new Proxy(data, {
get(target, p, receiver) {
return Reflect.get(target, p, receiver)
},
set(target, p, val, receiver) {
spanEl.innerText = val
inputEl.value = val
return Reflect.set(target, p, val, receiver)
}
})
function input(e) {
proxy.val = e.target.value
}
</script>
</body>
</html> |
|
let activeEffect = null;
let wm = new WeakMap();
function watchEffect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key);
return Reflect.get(target, key, receiver)
},
set(target, key, val, receiver) {
Reflect.set(target, key, val, receiver);
trigger(target, key);
}
})
}
function track(target, key) {
if (activeEffect) {
let map = wm.get(target);
if (!map) {
map = new Map();
wm.set(target, map);
}
let bucket = map.get(key);
if (!bucket) {
bucket = [];
map.set(key, bucket);
}
bucket.push(activeEffect);
}
}
function trigger(target, key) {
let map = wm.get(target);
if (map) {
let bucket = map.get(key);
if (bucket) {
bucket.forEach(item => item());
}
}
}
const t1 = reactive({a: 1, b: 2});
watchEffect(() => {
console.log(t1.a);
})
setTimeout(() => {
t1.a = 222;
}, 3000); |
No description provided.
The text was updated successfully, but these errors were encountered: