本次任务 前端
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对框架以及数据的操做有更深的理解, 受益不浅.
下一集:
你们均可以一块儿交流, 共同窗习,共同进步, 早日实现自我价值!!