本次任務 前端
vue3.0選擇了這個屬性, 雖然也會提供兼容版本, 但基本也算是跟老版ie說再見了, Proxy會解決以前沒法監聽數組的修改這個痛點, 也算是我輩前端的福音了.
使用方面會有很大不一樣, defineProperty是監控一個對象, 而Proxy是返回一個新對象, 這就須要我徹底重寫Observer模塊了, 話很少說先把基本功能演示一下.
由下面的代碼可知:vue
let ary = [1, 2, 3, 4]; let proxy = new Proxy(ary, { get(target, key) { return target[key]; }, set(target, key, value) { console.log('我被觸發了'); return value; } }); console.log(Array.isArray(proxy)); // true proxy.length = 1; // 我被觸發了
我以前寫的劫持模塊就須要完全改版了
cc_vue/src/Observer.js
改變$data指向我選擇在這裏作, 爲了保持主函數的純淨.ios
// 數據劫持 import { Dep } from './Watch'; let toString = Object.prototype.toString; class Observer { constructor(vm, data) { // 因爲Proxy的機制是返回一個代理對象, 那咱們就須要更改實例上的$data的指向了 vm.$data = this.observer(data); } } export default Observer;
observer
對象與數組是兩種循環的方式, 每次遞歸的解析裏面的元素, 最後整個對象徹底由Proxy組成.nginx
observer(data) { let type = toString.call(data), $data = this.defineReactive(data); if (type === '[object Object]') { for (let item in data) { data[item] = this.defineReactive(data[item]); } } else if (type === '[object Array]') { let len = data.length; for (let i; i < len; i++) { data[i] = this.defineReactive(data[i]); } } return $data; }
defineReactive
遇到基本類型我會直接return;
代理基本類型還會報錯😯;git
defineReactive(data) { let type = toString.call(data); if (type !== '[object Object]' && type !== '[object Array]') return data; let dep = new Dep(), _this = this; return new Proxy(data, { get(target, key) { Dep.target && dep.addSub(Dep.target); return target[key]; }, set(target, key, value) { if (target[key] !== value) { // 萬一用戶付給了一個新的對象, 就須要從新生成監聽元素了. target[key] = _this.observer(value); dep.notify(); } return value; } }); }
Observer模塊改裝完畢
如今vm上面的data已是Proxy代理的data了, 也挺費性能的, 因此說用vue開發的時候, 儘可能不要弄太多數據在data身上.github
這個屬性也蠻有趣的, 它的出現很符合設計模式, 數據就是要有一套專用的處理方法, 並且函數式處理更符合js的設計理念.web
下面把經常使用的方法演示一下
操做成功或失敗會返回布爾值ajax
let obj = {name:'lulu'}; console.log(Reflect.get(obj,'name')) // name console.log(Reflect.has(obj,'name')) // true console.log(Reflect.has(obj,'name1')) // false console.log(Reflect.set(obj,'age',24)) // true console.log(Reflect.get(obj,'age')) // 24
把個人代碼稍微改裝一下
cc_vue/src/index.js數據庫
proxyVm(data = {}, target = this) { for (let key in data) { Reflect.defineProperty(target, key, { enumerable: true, // 描述屬性是否會出如今for in 或者 Object.keys()的遍歷中 configurable: true, // 描述屬性是否配置,以及能否刪除 get() { return Reflect.get(data,key) }, set(newVal) { if (newVal !== data[key]) { Reflect.set(data,key,newVal) } } }); } }
我見過不少人離開axios或者jq中的ajax就無法作項目了, 其實徹底能夠本身封裝一個, 原理都差很少, 並且如今也能夠用'feach'弄, 條件容許的狀況下真的不必定非要依賴插件.
獨立的文件夾負責網絡相關的事宜;
cc_vue/use/httpnpm
class C_http { constructor() { // 請求可能不少, 而且須要互不干涉, 因此決定每一個類生成一個獨立的請求 let request = new XMLHttpRequest(); request.responseType = 'json'; this.request = request; } }
編寫插件的時候, 先要考慮用戶會怎麼用它
http.get('http:xxx.com', { name: 'lulu'}).then(data => {}); http.post('http:xxx.com', { name: 'lulu'}).then(data => {});
get與post方法其實不用每次都初始化, 咱們直接寫在外面
處理好參數直接調用open方法, 進入open狀態某些參數才能設置;
在有參數的狀況下爲連接添加'?';
參數品在連接後面, 我以前遇到一個bug, 拼接參數的時候若是結尾是'&'部分手機出現跳轉錯誤, 因此爲了防止特殊狀況的發生, 咱們要判斷一下幹掉結尾的'&';
function get(path, data) { let c_http = new C_http(); let str = '?'; for (let i in data) { str += `${i}=${data[i]}&`; } if (str.charAt(str.length - 1) === '&') { str = str.slice(0, -1); } path = str === '?' ? path : `${path}${str}`; c_http.request.open('GET', path); return c_http.handleReadyStateChange(); }
post
這個就很好說了, .data是請求自帶的.
function post(path, data) { let c_http = new C_http(); c_http.request.open('POST', path); c_http.data = data; return c_http.handleReadyStateChange(); }
handleReadyStateChange
handleReadyStateChange() { // 這個須要在open以後寫 // 設置數據類型 this.request.setRequestHeader( 'content-type', 'application/json;charset=utf-8' ); // 如今前端全部返回都是Promise化; return new Promise((resolve) => { this.request.onreadystatechange = () => { // 0 UNSENT 代理被建立,但還沒有調用 open() 方法。 // 1 OPENED open() 方法已經被調用。 // 2 HEADERS_RECEIVED send() 方法已經被調用,而且頭部和狀態已經可得到。 // 3 LOADING 下載中; responseText 屬性已經包含部分數據。 // 4 DONE 下載操做已完成。 if (this.request.readyState === 4) { // 這裏由於是獨立開發, 就直接寫200了, 具體項目裏面會比較複雜 if (this.request.status === 200) { // 返回值都在response變量裏面 resolve(this.request.response); } } }; // 真正的發送事件. this.send(); }); }
send
send() { // 數據必定要JSON處理一下 this.request.send(JSON.stringify(this.data)); }
不少人提到 "攔截器" 會感受很高大上, 其實真的沒啥
簡易的攔截器"interceptors"👇
// 1: 使用對象不使用[]是由於能夠高效的刪除攔截器 const interceptorsList = {}; // 2: 每次發送數據以前執行全部攔截器, 別忘了把請求源傳進去. send() { for (let i in interceptorsList) { interceptorsList[i](this); } this.request.send(JSON.stringify(this.data)); } // 3: 添加與刪除攔截器的方法, 沒啥東西因此直接協議期了. function interceptors(cb, type) { if (type === 'remove') { delete interceptorsList[cb]; } else if (typeof cb === 'function') { interceptorsList[cb] = cb; } }
邊邊角角的小功能
class C_http { constructor() { let request = new XMLHttpRequest(); request.timeout = 5000; request.responseType = 'json'; request.ontimeout = this.ontimeout; this.request = request; } ontimeout() { throw new Error('超時了,快檢查一下'); } abort() { this.request.abort(); } }
簡易的'axios'就作好, 普通的請求都沒問題的
請求作好了, 固然要啓動服務了, 本次就不鏈接數據庫了, 要否則就跑題了.
koa2
不瞭解koa的同窗跟着作也沒問題
npm install koa-generator -g
Koa2 項目名
cc_vue/use/server 是本次工程的服務相關存放處.
cc_vue/use/server/bin/www
端口號能夠隨意更改, 當時9999被佔了我就設了9998;
const pros = '9998'; var port = normalizePort(process.env.PORT || pros);
cc_vue/use/server/routes/index.js
這個頁面就是專門處理路由相關, koa很貼心, router.get就是處理get請求.
每一個函數必須寫async也是爲了著名的'洋蔥圈'.
想了解更多相關知識能夠去看koa教程, 我也是用到的時候纔會去看一眼.
寫代碼的時候遇到須要測試延遲相關的時候, 不要總用定時器, 要多本身啓動服務.
const router = require('koa-router')(); router.get('/', async (ctx, next) => { ctx.body = { data: '我是數據' }; }); router.post('/', async (ctx, next) => { ctx.body = ctx.request.body; }); module.exports = router;
寫到如今能夠開始跑起來試試了
😺一個很傳統的問題出現了'跨域'.
這裏咱們簡單的選擇插件來解決, 十分粗暴.
cc_vue/use/server/app.js
npm install --save koa2-cors
var cors = require('koa2-cors'); app.use(cors());
既然說到這裏就, 那就總結一下吧
跨域的幾種方式
本次測試的dom結構
<div id="app"> <p>n: {{ n.length }}</p> <p>m: {{ m }}</p> <p>n+m: {{ n.length + m }}</p> <p>{{ http }}</p> </div>
let vm = new C({ el: '#app', data: { n: [1, 2, 3], m: 2, http: '等待中' } }); http.get('http://localhost:9998/', { name: 'lulu', age: '23' }).then(data => { vm.http = data.data; vm.n.length = 1 vm.n.push('22') });
具體效果請在工程裏面查看
作這個工程能讓本身對vue對框架以及數據的操做有更深的理解, 受益不淺.
下一集:
你們均可以一塊兒交流, 共同窗習,共同進步, 早日實現自我價值!!