接上,
new一个实例对象,vc,构造函数动态绑定一个空对象,并在构造函数上绑定静态方法
$on进行事件的注册,$emit抛出执行事件
function observe() {
// 利用策略模式-可以快速根据特定的事件,执行多个函数
this.strategy = {
}
}
// 在observe构造函数的原型上添加两个静态方法$on和$emit
// $emit调用传入参数,通过属性名找到方法,执行所有事件(被发布的事件,订阅者获取将执行所有事件)
observe.prototype.$emit = function (eventName) {
this.strategy[eventName].forEach(fn => fn())
}
// $on调用传入两个参数,第一个事件名,第二个事件执行函数--会被push到对象中
observe.prototype.$on = function (eventName, callback) {
// 判断里面有没有这个事件名,没有就添加键值
if (!this.strategy[eventName]) {
this.strategy[eventName] = []
}
this.strategy[eventName].push(callback)
}
const vc = new observe()
// 理解为在methods中定义执行函数
function doclick() {
console.log("起身");
}
// 定义一个事件,执行函数----发布了一个事件
vc.$on('qisheng', doclick)
抛出执行事件
使用$on添加事件,$emit抛出执行事件
接上次目标
数据修改,视图更新--和模拟实现v-model的双向绑定
先实现v-html的数据改动视图更新---
当订阅者关注发生改变的时候执行事件更新视图
(之前的错误,写死了,写data.name的话只会data.name会更新数据,应该改为key)
修改后试试确定没问题
更新视图
实现演示
实现v-model双向--从视图到数据
首先数据更新视图也更新和上面v-html一样添加一个$on
前面set方法里已经使用$emit更新视图了,这样就可以了实现数据变化绑定v-model的input数据变化
监听input事件,事件对象e,的target的value有input框输入的值,并把值赋值给实例对象里的key(age或name)
实现双向绑定演示
实现效果完整代码
<body>
<div id="app">
<h1 v-html="name"></h1>
<input v-model="name" type="text">
<h2 v-html="name" data-html="name"></h2>
<input v-model="age" data-html="name"></input>
<h3 v-html="age"></h3>
</div>
<script>
// // 观察者
// function observe() {
// }
function observe() {
// 利用策略模式-可以快速根据特定的事件,执行多个函数
this.strategy = {
}
}
// 在observe构造函数的原型上添加两个静态方法$on和$emit
// $emit调用传入参数,通过属性名找到方法,执行所有事件(被发布的事件,订阅者获取将执行所有事件)
observe.prototype.$emit = function (eventName) {
this.strategy[eventName].forEach(fn => fn())
}
// $on调用传入两个参数,第一个事件名,第二个事件执行函数--会被push到对象中
observe.prototype.$on = function (eventName, callback) {
// 判断里面有没有这个事件名,没有就添加键值
if (!this.strategy[eventName]) {
this.strategy[eventName] = []
}
this.strategy[eventName].push(callback)
}
// const vc = new observe()
// // 理解为在methods中定义执行函数
// function doclick() {
// console.log("起身");
// }
// // 定义一个事件,执行函数----发布了一个事件
// vc.$on('qisheng', doclick)
</script>
<script>
const vc = new observe()
function MVVM(options) {
const { el, data } = options
console.log(el);
console.log(data);
for (let key in data) {
console.log(key);
Object.defineProperty(this, key, {
get: function () {
return data[key]
},
set: function (newVal) {
console.log(newVal, '修改了值');
// 修改值和原先值不同才会触发
if (data[key] !== newVal) {
data[key] = newVal
vc.$emit(key)
}
}
})
}
// 显示数据//挂载的节点,下的所有元素---得到伪数组
const domArr = document.querySelector(el).children
// 转换为真数组
console.log(Array.from(domArr), '转换');
Array.from(domArr).forEach(domNode => {
console.log(domNode);
console.log(domNode.dataset.html, 'dataset取自定义属性值');
// console.log(domNode.hasAttribute('v-html'));
if (domNode.hasAttribute('v-html')) {
console.log(domNode.getAttribute('v-html'));
const key = domNode.getAttribute('v-html')
domNode.innerHTML = this[key]//this指向实例化对象
// ------------
// 发布一个事件
vc.$on(key, () => { domNode.innerHTML = this[key] })
}
if (domNode.hasAttribute('v-model')) {
// console.log(domNode.getAttribute('v-html'));
const key = domNode.getAttribute('v-model')
domNode.value = this[key]//this指向实例化对象
vc.$on(key, () => { domNode.value = this[key] })
// 监听input事件,事件对象e,的target的value有input框输入的值,并把值赋值给实例对象里的key(age或name)
domNode.addEventListener('input', (e) => {
this[key]= e.target.value
})
}
})
}
// 语法 dataset 也可以取自定义属性值,但是标签绑定固定语法 data-自定义名="值",取出标签元素.dataset.自定义名,返回自定义属性值
// 语法getAttribute,返回自定义属性值,元素.hasAttribute('自定义属性名'),返回自定义属性值
// 语法hasAttribute,返回布尔值,元素.hasAttribute('自定义属性'),判断节点是是否存在此自定义属性
const vm = new MVVM({
el: '#app',
data: {
name: "张三",
age:18
},
})
console.dir(vm)
</script>
</body>