1. 程式人生 > >MySQL中間件之ProxySQL(8):SQL語句的重寫規則極速賽車ProxySQL(8):

MySQL中間件之ProxySQL(8):SQL語句的重寫規則極速賽車ProxySQL(8):

prot mvvm xxx 復制 初始化 -a data屬性 不能 所有

聯系方式:QQ:2747044651 網址http://zhengtuwl.com
的根元素“#mvvm-app”內只有一個文本節點#text,#text的內容為{{name}}。我們就以下面這個模板詳細了解一下VUE框架的大體實現流程。
<div id="mvvm-app">
{{name}}
</div>
<script src="./js/observer.js"></script>
<script src="./js/watcher.js"></script>
<script src="./js/compile.js"></script>
<script src="./js/mvvm.js"></script>
<script>
let vm = new MVVM({
el: "#mvvm-app",
data: {
name: "hello world"
},
})

</script>
? 1
? 2
? 3
? 4
? 5
? 6
? 7
? 8
? 9
? 10
? 11
? 12
? 13
? 14
? 15
? 16
? 17

復制代碼
數據代理
1、什麽是數據代理
在vue裏面,我們將數據寫在data對象中。但是我們在訪問data裏的數據時,既可以通過vm.data.name訪問,也可以通過vm.name訪問。這就是數據代理:在一個對象中,可以動態的訪問和設置另一個對象的屬性。

2、實現原理
我們知道靜態綁定(如vm.name = vm.data.name)可以一次性的將結果賦給變量,而使用Object.defineProperty()方法來綁定則可以通過set和get函數實現賦值的中間過程,從而實現數據的動態綁定。具體實現如下:
復制代碼
let obj = {};
let obj1 = {
name: ‘xiaoyu’,
age: 18,
}
//實現origin對象代理target對象
function proxyData(origin,target){
Object.keys(target).forEach(function(key){
Object.defineProperty(origin,key,{//定義origin對象的key屬性
enumerable: false,
configurable: true,
get: function getter(){
return target[key];//origin[key] = target[key];
},
set: function setter(newValue){
target[key] = newValue;
}
})
})
}
復制代碼
vue中的數據代理也是通過這種方式來實現的。
復制代碼
function MVVM(options) {
this.options=options||;vardata=this.data=this.options=options||;vardata=this.data=this.options.data;
var _this = this;//當前實例vm
// 數據代理
// 實現 vm._data.xxx -> vm.xxx
Object.keys(data).forEach(function(key) {
_this._proxyData(key);
});
observe(data, this);
this.$compile = new Compile(options.el || document.body, this);
? 1
? 2
? 3
? 4
? 5
? 6
? 7
? 8
}
MVVM.prototype = {
_proxyData: function(key) {
var _this = this;
if (typeof key == ‘object’ && !(key instanceof Array)){//這裏只實現了對對象的監聽,沒有實現數組的
this._proxyData(key);
}
Object.defineProperty(_this, key, {
configurable: false,
enumerable: true,
get: function proxyGetter() {
return _this._data[key];
},
set: function proxySetter(newVal) {
_this._data[key] = newVal;
}
});
},
};
復制代碼
實現Observe
1、雙向數據綁定
數據變動  —>  視圖更新
視圖更新  —>  數據變動
要想實現當數據變動時視圖更新,首先要做的就是如何知道數據變動了,可以通過Object.defineProperty()函數監聽data對象裏的數據,當數據變動了就會觸發set()方法。所以我們需要實現一個數據監聽器Observe,來對數據對象中的所有屬性進行監聽,當某一屬性數據發生變化時,拿到最新的數據通知綁定了該屬性的訂閱器,訂閱器再執行相應的數據更新回調函數,從而實現視圖的刷新。
當設置this.name = ‘hello vue’時,就會執行set函數,通知訂閱器裏的訂閱者執行相應的回調函數,實現數據變動,對應視圖更新。
復制代碼
function observe(data){
if (typeof data != ‘object’) {
return ;
}
return new Observe(data);
}
function Observe(data){
this.data = data;
this.walk(data);
}
Observe.prototype = {
walk: function(data){
let _this = this;
for (key in data) {
if (data.hasOwnProperty(key)){
let value = data[key];
if (typeof value == ‘object’){
observe(value);
}
_this.defineReactive(data,key,data[key]);
}
}
},
defineReactive: function(data,key,value){
Object.defineProperty(data,key,{
enumerable: true,//可枚舉
configurable: false,//不能再define
get: function(){
console.log(‘你訪問了’ + key);return value;
},
set: function(newValue){
console.log(‘你設置了’ + key);
if (newValue == value) return;
value = newValue;
observe(newValue);//監聽新設置的值
}
})
}
}
復制代碼
2、實現一個訂閱器
要想通知訂閱者,首先得要有一個訂閱器(統一管理所有的訂閱者)。為了方便管理,我們會為每一個data對象的屬性都添加一個訂閱器(new Dep)。
訂閱器裏存著的是訂閱者Watcher(後面會講到),由於訂閱者可能會有多個,我們需要建立一個數組來維護。一旦數據變化,就會觸發訂閱器的notify()方法,訂閱者就會調用自身的update方法實現視圖更新。
復制代碼
function Dep(){
this.subs = [];
}
Dep.prototype = {
addSub: function(sub){this.subs.push(sub);
},
notify: function(){
this.subs.forEach(function(sub) {
sub.update();
})
}
}
復制代碼
每次響應屬性的set()函數調用的時候,都會觸發訂閱器,所以代碼補充完整。
復制代碼
Observe.prototype = {
//省略的代碼未作更改
defineReactive: function(data,key,value){
let dep = new Dep();//創建一個訂閱器,會被閉包在key屬性的get/set函數內,因此每個屬性對應唯一一個訂閱器dep實例
Object.defineProperty(data,key,{
enumerable: true,//可枚舉
configurable: false,//不能再define
get: function(){
console.log(‘你訪問了’ + key);
return value;
},
set: function(newValue){
console.log(‘你設置了’ + key);
if (newValue == value) return;
value = newValue;
observe(newValue);//監聽新設置的值
dep.notify();//通知所有的訂閱者
}
})
}
}
復制代碼
實現Complie
compile主要做的事情是解析模板指令,將模板中的data屬性替換成data屬性對應的值(比如將{{name}}替換成data.name值),然後初始化渲染頁面視圖,並且為每個data屬性添加一個監聽數據的訂閱者(new Watcher),一旦數據有變動,收到通知,更新視圖。
遍歷解析需要替換的根元素el下的HTML標簽必然會涉及到多次的DOM節點操作,因此不可避免的會引發頁面的重排或重繪,為了提高性能和效率,我們把根元素el下的所有節點轉換為文檔碎片fragment進行解析編譯操作,解析完成,再將fragment添加回原來的真實dom節點中。
註:文檔碎片本身也是一個節點,但是當將該節點append進頁面時,該節點標簽作為根節點不會顯示html文檔中,其裏面的子節點則可以完全顯示。
Compile解析模板,將模板內的子元素#text添加進文檔碎片節點fragment。
復制代碼
function Compile(el,vm){
this.vm=vm;//vm為當前實例this.vm=vm;//vm為當前實例this.el = document.querySelector(el);//獲得要解析的根元素
if (this.el){
this.fragment=this.nodeToFragment(this.fragment=this.nodeToFragment(this.el);
this.init();
this.el.appendChild(this.el.appendChild(this.fragment);
}
}
Compile.prototype = {
nodeToFragment: function(el){
let fragment = document.createDocumentFragment();
let child;

MySQL中間件之ProxySQL(8):SQL語句的重寫規則極速賽車ProxySQL(8):