Vue Object.defineProperty 및 ProxyVue 양 방향 데이터 바 인 딩 실현
다음 방안 에서 의 실현 방향:
<!DOCTYPE html>
<html>
<head>
<title>myVue</title>
<style>
#app{
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<form>
<input type="text" v-model="number" />
<button type="button" v-click="increment"> </button>
</form>
<h3 v-bind="number"></h3>
</div>
</body>
<script>
// myVue
function myVue(option) {
this._init(option)
}
myVue.prototype._init = function (options) { //
this.$options = options // options , el,data,methods
this.$el = document.querySelector(options.el) // el #app, this.$el id app Element
this.$data = options.data // this.$data = {number: 0}
this.$methods = options.methods // this.$methods = {increment: function(){}}
// _binding model view , Watcher 。 model , , view
this._binding = {}
this._obsever(this.$data)
this._compile(this.$el)
}
// :
myVue.prototype._obsever = function (obj) {
let _this = this
Object.keys(obj).forEach((key) => { // obj
if (obj.hasOwnProperty(key)) { // obj key
_this._binding[key] = [] // ,_binding = {number: []} new Watcher
}
let value = obj[key]
if (typeof value === 'object') { // ,
_this._obsever(value)
}
Object.defineProperty(_this.$data, key, {
enumerable: true,
configurable: true,
get: () => { // value
return value
},
set: (newVal) => { // value
if (value !== newVal) {
value = newVal
_this._binding[key].forEach((item) => { // number , _binding[number] Watcher
item.update() // Watcher update DOM
})
}
}
})
})
}
// : , DOM
function Watcher(el, data, key, attr) {
this.el = el // DOM
this.data = data // this.$data : {number: 0, count: 0}
this.key = key // , "number"
this.attr = attr // , "innerHTML","value"
this.update()
}
// H3.innerHTML = this.data.number; number , update , DOM
Watcher.prototype.update = function () {
this.el[this.attr] = this.data[this.key]
}
// view model , (v-bind,v-model,v-clickde)
myVue.prototype._compile = function (el) { // root id app Element ,
let _this = this
let nodes = Array.prototype.slice.call(el.children) //
nodes.map(node => {
if (node.children.length && node.children.length > 0) { // ,
_this._compile(node)
}
if (node.hasAttribute('v-click')) { // v-click , onclick , increment , number++
let attrVal = node.getAttribute('v-click')
node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind data method
}
// v-model , INPUT TEXTAREA, input
if (node.hasAttribute('v-model') && (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')) {
let attrVal = node.getAttribute('v-model')
_this._binding[attrVal].push(new Watcher(
node, // DOM
_this.$data,
attrVal, // v-model
'value'
))
node.addEventListener('input', () => {
_this.$data[attrVal] = node.value // number node value ,
})
}
if (node.hasAttribute('v-bind')) {
let attrVal = node.getAttribute('v-bind')
_this._binding[attrVal].push(new Watcher(
node,
_this.$data,
attrVal, // v-bind
'innerHTML'
))
}
})
}
window.onload = () => { // ,
new myVue({
el: '#app',
data: {
number: 0,
count: 0
},
methods: {
increment() {
this.number++
},
incre() {
this.count++
}
}
})
}
</script>
</html>
2.Proxy 양 방향 데이터 바 인 딩 실현
<!DOCTYPE html>
<html>
<head>
<title>myVue</title>
<style>
#app{
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<form>
<input type="text" v-model="number" />
<button type="button" v-click="increment"> </button>
</form>
<h3 v-bind="number"></h3>
</div>
</body>
<script>
// myVue
function myVue(option) {
this._init(option)
}
myVue.prototype._init = function (options) { //
this.$options = options // options , el,data,methods
this.$el = document.querySelector(options.el) // el #app, this.$el id app Element
this.$data = options.data // this.$data = {number: 0}
this.$methods = options.methods // this.$methods = {increment: function(){}}
this._binding = {}
this._obsever(this.$data)
this._complie(this.$el)
}
// :
myVue.prototype._obsever = function (data) {
let _this = this
let handler = {
get(target, key) {
return target[key]; // key
},
set(target, key, newValue) {
let res = Reflect.set(target, key, newValue); //
_this._binding[key].map(item => {
item.update();
});
return res;
}
};
// this.$data, this.$data , this.$data , handler
this.$data = new Proxy(data, handler);
}
// view model , (v-bind,v-model,v-clickde)
myVue.prototype._complie = function (el) { // el id app Element ,
let _this = this
let nodes = Array.prototype.slice.call(el.children) //
nodes.map(node => {
if (node.children.length && node.children.length > 0) this._complie(node)
if (node.hasAttribute('v-click')) { // v-click , onclick , increment , number++
let attrVal = node.getAttribute('v-click')
node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind data method
}
// v-model , INPUT TEXTAREA, input
if (node.hasAttribute('v-model') && (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')) {
let attrVal = node.getAttribute('v-model')
console.log(_this._binding)
if (!_this._binding[attrVal]) _this._binding[attrVal] = []
_this._binding[attrVal].push(new Watcher(
node, // DOM
_this.$data,
attrVal, // v-model
'value',
))
node.addEventListener('input', () => {
_this.$data[attrVal] = node.value // number node value ,
})
}
if (node.hasAttribute('v-bind')) {
let attrVal = node.getAttribute('v-bind')
if (!_this._binding[attrVal]) _this._binding[attrVal] = []
_this._binding[attrVal].push(new Watcher(
node,
_this.$data,
attrVal, // v-bind
'innerHTML',
))
}
})
}
// , DOM
function Watcher(el, data, key, attr) {
this.el = el // DOM
this.data = data // this.$data : {number: 0, count: 0}
this.key = key // , "num"
this.attr = attr // , "innerHTML","value"
this.update()
}
// H3.innerHTML = this.data.number; number , update , DOM
Watcher.prototype.update = function () {
this.el[this.attr] = this.data[this.key]
}
window.onload = () => { // ,
new myVue({
el: '#app',
data: {
number: 0,
count: 0
},
methods: {
increment() {
this.number++
},
incre() {
this.count++
}
}
})
}
</script>
</html>
3.위의 코드 를 class 의 쓰기 로 변경 합 니 다.
<!DOCTYPE html>
<html>
<head>
<title>myVue</title>
<style>
#app{
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<form>
<input type="text" v-model="number" />
<button type="button" v-click="increment"> </button>
</form>
<h3 v-bind="number"></h3>
</div>
</body>
<script>
class MyVue {
constructor(options) { //
this.$options = options // options , el,data,methods
this.$el = document.querySelector(options.el) // el #app, this.$el id app Element
this.$data = options.data // this.$data = {number: 0}
this.$methods = options.methods // this.$methods = {increment: function(){}}
this._binding = {}
this._obsever(this.$data)
this._complie(this.$el)
}
_obsever (data) { // :
let _this = this
let handler = {
get(target, key) {
return target[key]; // key
},
set(target, key, newValue) {
let res = Reflect.set(target, key, newValue); //
_this._binding[key].map(item => {
item.update();
});
return res;
}
};
// this.$data, this.$data , this.$data , handler
this.$data = new Proxy(data, handler);
}
_complie(el) { // el id app Element ,
let _this = this
let nodes = Array.prototype.slice.call(el.children) //
nodes.map(node => {
if (node.children.length && node.children.length > 0) this._complie(node)
if (node.hasAttribute('v-click')) { // v-click , onclick , increment , number++
let attrVal = node.getAttribute('v-click')
node.onclick = _this.$methods[attrVal].bind(_this.$data) // bind data method
}
// v-model , INPUT TEXTAREA, input
if (node.hasAttribute('v-model') && (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')) {
let attrVal = node.getAttribute('v-model')
if (!_this._binding[attrVal]) _this._binding[attrVal] = []
_this._binding[attrVal].push(new Watcher(
node, // DOM
_this.$data,
attrVal, // v-model
'value',
))
node.addEventListener('input', () => {
_this.$data[attrVal] = node.value // number node value ,
})
}
if (node.hasAttribute('v-bind')) {
let attrVal = node.getAttribute('v-bind')
if (!_this._binding[attrVal]) _this._binding[attrVal] = []
_this._binding[attrVal].push(new Watcher(
node,
_this.$data,
attrVal, // v-bind
'innerHTML',
))
}
})
}
}
class Watcher {
constructor (el, data, key, attr) {
this.el = el // DOM
this.data = data // this.$data : {number: 0, count: 0}
this.key = key // , "num"
this.attr = attr // , "innerHTML","value"
this.update()
}
update () {
this.el[this.attr] = this.data[this.key]
}
}
window.onload = () => { // ,
new MyVue({
el: '#app',
data: {
number: 0,
count: 0
},
methods: {
increment() {
this.number++
},
incre() {
this.count++
}
}
})
}
</script>
</html>
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.