面壁人浮川 发布的文章 - 浮川的小窝
首页
休闲直播
4K壁纸
统计
更多
关于
留言
归档
搜 索
1
HelloWorld!
138 阅读
2
前端算法整理
129 阅读
3
关于服务器配置反代隐藏端口中遇到的问题
104 阅读
4
maptalks 一些基础api的再封装(待解耦改装纯方法类)
95 阅读
5
HTTPS原理和通信流程
94 阅读
生活
学习
随笔
吐槽
小秘密
小故事
登录
/
注册
搜 索
SnowLove
累计撰写
65
篇文章
累计收到
5
条评论
首页
栏目
生活
学习
随笔
吐槽
小秘密
小故事
页面
休闲直播
4K壁纸
统计
关于
留言
归档
用户登录
登录
注册
找到
65
篇与
面壁人浮川
相关的结果
2023-12-31
vue2源码学习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> html,body{ width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="app"></div> <script src="../dist/vue.js"></script> <script> Vue.component("my",{ render(h){ return h('div','我是组件测试组件渲染流程') } }) let vm = new Vue({ el:"#app", render(h){ return h('my') } }) </script> </body> </html>流程 // (一)创建全局组件 /* src/core/global-api/assets.js */ 1.definition = this.options._base.extend(definition) // 执行 2.this.options[type + 's'][id] = definition // 在vue实例 options上绑定组件名称 /* src/core/global-api/extend.js */ 1.Vue.extend (){ // ... return Sub } // 执行extend方法并返回Sub 2.const Sub = function VueComponent (options) { this._init(options) } Sub.options = mergeOptions( Super.options, extendOptions ) // 创建sub子类并合并vue函数上定义的各种方法 // (二)创建vue对象 (一)创建全局组件 /* src/core/instance/index.js */ 1.function Vue (options) { this._init(options) } // 创建vue对象并执行_init方法 /* src/core/instance/init.js */ 2.Vue.prototype._init = function (options?: Object) { // ... initLifecycle(vm) // 绑定父子关系 initEvents(vm) // 初始化时间 initRender(vm) // 初始化渲染 callHook(vm, 'beforeCreate') // 生命周期 initInjections(vm) // inject initState(vm) // data属性监听 响应式 initProvide(vm) // provide callHook(vm, 'created') // 生命周期 // ... if (vm.$options.el) { vm.$mount(vm.$options.el) } } // 初始化方法 响应式等 vm.$mount执行挂载 /* src/platforms/web/entry-runtime-with-compiler.js */ 3.Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { const = compileToFunctions(template, { outputSourceRange: process.env.NODE_ENV !== 'production', shouldDecodeNewlines, shouldDecodeNewlinesForHref, delimiters: options.delimiters, comments: options.comments }, this) options.render = render options.staticRenderFns = staticRenderFns return mount.call(this, el, hydrating) } // 重写Vue.prototype.$mount方法 解析template模板 绑定到this上 执行原$mount方法 /* src/platforms/web/runtime/index.js */ 4.Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) } // 执行mountComponent /* src/core/instance/lifecycle.js */ 5.export function mountComponent ( vm: Component, el: ?Element, hydrating?: boolean ): Component { callHook(vm, 'beforeMount') updateComponent = () => { vm._update(vm._render(), hydrating) } new Watcher(vm, updateComponent, noop, { before () { if (vm._isMounted && !vm._isDestroyed) { callHook(vm, 'beforeUpdate') } } }, true /* isRenderWatcher */) } // 创建组件渲染Watcher /* src/core/observer/watcher.js */ 6.export default class Watcher { constructor (){ if (typeof expOrFn === 'function') { this.getter = expOrFn } this.value = this.lazy ? undefined : this.get() } get () { pushTarget(this) let value const vm = this.vm try { value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "$"`) } else { throw e } } finally { if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() } return value } } // 渲染watcher获取 获取回调 updateComponent = () => 执行 /* src/core/instance/render.js */ 7.Vue.prototype._render = function (): VNode { vnode = render.call(vm._renderProxy, vm.$createElement) } // 执行render(h)h为$createElement方法创建vnode /* src/core/vdom/create-element.js */ 8.export function createElement ( context: Component, tag: any, data: any, children: any, normalizationType: any, alwaysNormalize: boolean ): VNode | Array<VNode> { return _createElement(context, tag, data, children, normalizationType) } // 创建vnode元素 export function _createElement ( context: Component, // vue实例 tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number ): VNode | Array<VNode> { let Ctor if (typeof tag === 'string') { else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) // 获取全局组件绑定在vue函数上的全局组件 { // component vnode = createComponent(Ctor, data, context, children, tag) // 创建vnode } } }// 创建Ctor和vnode元素 /* src/core/vdom/create-component.js */ 9.export function createComponent ( Ctor: Class<Component> | Function | Object | void, // 子类my 合并了vue上的¥options data: ?VNodeData, context: Component, // vue实例对象 children: ?Array<VNode>, tag?: string ): VNode | Array<VNode> | void { const baseCtor = context.$options._base //_base等于vue函数 Vue (options) // extract props const propsData = extractPropsFromVNodeData(data, Ctor, tag) const listeners = data.on // replace with listeners with .native modifier // so it gets processed during parent component patch. data.on = data.nativeOn // install component management hooks onto the placeholder node installComponentHooks(data) // 创建一个包裹住my组件的父容器组件 vue-component-1-my const vnode = new VNode( `vue-component-$$` : ''}`, data, undefined, undefined, undefined, context, , asyncFactory ) else if (isDef(vnode)) { if (isDef(ns)) applyNS(vnode, ns) if (isDef(data)) registerDeepBindings(data) return vnode } } // 创建包裹my子组件的父组件vue-component-1-my的vnode元素 // 查看图1 返回第7步 /* src/core/instance/render.js */ 10.Vue.prototype._render = function (): VNode { return vnode } // 返回vue-component-1-my vnode // 返回第5步 updateComponent /* src/core/instance/lifecycle.js */ 11.Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this // 这个vm应为vue创建的的实例对象 if (!prevVnode) { // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */) } // 更新页面 } /* src/core/vdom/patch.js */ 12. return function patch (oldVnode, vnode, hydrating, removeOnly) { const isRealElement = isDef(oldVnode.nodeType) if (isRealElement) { oldVnode = emptyNodeAt(oldVnode) // oldVnode = #app元素赋值 } // create new node createElm( vnode, insertedVnodeQueue, // extremely rare edge case: do not insert if old element is in a // leaving transition. Only happens when combining transition + // keep-alive + HOCs. (#4590) oldElm._leaveCb ? null : parentElm, nodeOps.nextSibling(oldElm) ) } function createElm ( vnode, // vue-component-1-my insertedVnodeQueue, // [] parentElm, // body dom元素 refElm, nested, ownerArray, index ) { if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) { return } } function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) { if (isDef(i = i.hook) && isDef(i = i.init)) { i(vnode, false /* hydrating */) }// 执行组件 hooks生命周期 (init,prepatch,insert,destroy)中的init } /* src/core/vdom/create-component.js */ 13.const componentVNodeHooks = { init (vnode: VNodeWithData, hydrating: boolean): ?boolean { else { const child = vnode.componentInstance = createComponentInstanceForVnode( vnode, activeInstance ) child.$mount(hydrating ? vnode.elm : undefined, hydrating) } }, } export function createComponentInstanceForVnode ( vnode: any, parent: any, ): Component { const options: InternalComponentOptions = { _isComponent: true, _parentVnode: vnode, parent } // check inline-template render functions const inlineTemplate = vnode.data.inlineTemplate return new vnode.componentOptions.Ctor(options) } // 执行全局组件my的this._init(options)方法 // 返回(一)创建全局组件 第2步 查看图二options参数的值 // 再次执行(二)创建vue对象 第2步 执行完后回到第13步 child.$mount(hydrating ? vnode.elm : undefined, hydrating) // 再次执行4、5、6步后 返回第12步 // 其中第五步vm._update(vm._render(), hydrating) // vm._render()返回my组件的vnode // vm._update执行最终页面dom渲染 /* src/core/instance/lifecycle.js */ Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this if (!prevVnode) { // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */) } else { // updates vm.$el = vm.__patch__(prevVnode, vnode) } restoreActiveInstance() if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } } // 执行__patch__ 更新页面 将最终真实#app 下render函数中的 // 内容转换为真实dom赋值给vm.$el /* src/core/vdom/patch.js */ 14.return function patch (oldVnode, vnode, hydrating, removeOnly) { createElm(vnode, insertedVnodeQueue) return vnode.elm } function createElm ( vnode, insertedVnodeQueue, parentElm, refElm, nested, ownerArray, index ) { // ... vnode.elm = vnode.ns ? nodeOps.createElementNS(vnode.ns, tag) : nodeOps.createElement(tag, vnode) // 创建my组件 vnode中的elm属性 = dom元素 createChildren(vnode, children, insertedVnodeQueue) // 递归创建my组件中的子元素标签(已转换为vnode) insert(parentElm, vnode.elm, refElm) // 递归插入到子元素的父级elm中 }// 将my组件嵌套的vode中的elm创建出来 // 返回到patch return vnode.elm // 返回到第13步_update // 返回到6步 value = this.getter.call(vm, vm) // 返回到第5步 mountComponent // 返回到第4步 runtime/index.js Vue.prototype.$mount // 返回到第3步 entry-runtime-with-compiler.js Vue.prototype.$mount // 返回到第13步 componentVNodeHooks // 返回到第9步 vdom/create-component.js createComponent function initComponent (vnode, insertedVnodeQueue) { if (isDef(vnode.data.pendingInsert)) { insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert) vnode.data.pendingInsert = null } vnode.elm = vnode.componentInstance.$el if (isPatchable(vnode)) { invokeCreateHooks(vnode, insertedVnodeQueue) setScope(vnode) } else { registerRef(vnode) insertedVnodeQueue.push(vnode) } } // 将组件elm插入页面中 // 返回第12步 createElm // 流程结束
2023年12月31日
0
0
0
2023-12-07
emby+alist3+cloudDriver2 emby无法播放网盘资源问题
这阵子捣鼓新服务器 没抽出手来搞这个emby 随手点开个视频就是下面这个吊样子 :@(愤怒) :@(愤怒) :@(愤怒) 血压瞬间拉满 对于强迫症的我 放到媒体库里的视频看不了?这不就跟家里藏着个金娇缺只能天天压着枪看着 那是不可能的 :@(深思) :@(深思) :@(深思) 今天终于整理好心情放下手头的活好好治治这个小浪蹄子 :@(皱眉)行动一不管三七二十一 先把emby的版本从4.7升级到4.8先 不排除低版本ffmpeg的版本无法解析视频的问题 然后就是一通百度google阿里云找资源 心路历程不必言表 最后还是回归到了矿神大大的套件 :@(吐血倒地) :@(吐血倒地) 现在版本升到最新了 屌错误依然涛声依旧 :@(无语)行动二因为我的nas上资源来源比较杂 有存储空间里的 有外置硬盘盒里的 还有各网盘里的 林林总总的资源多而杂 就想着用emby指定好媒体库进行统一管理 ps:想过用nastool进行资源整合 但是这样把资源放到本地 一是本地没有这么大的空间存储 二十白白浪费了网盘的空间资源 所以犹犹豫豫也就没有用nastool进行管理这次我不在随机查看视频 而是选了上述三个来源的视频个几个进行测试这次的测试让我发现了问题 嗯= =一个很愚蠢的问题 :@(尴尬) 发现的过程是我本地的资源、外置硬盘盒视频都可以正常播放 但是唯独网盘播放不了 于是到浏览器控制台查看接口报错 好嘛 视频播放接口一直在报错 原因是找不到文件地址 此时我就纳闷了 前阵子还刮过屑 怎么这阵子突然就不好用了?是不是cloudDriver挂载掉了?或者alist token过期了?行动三有了目标就好处理 我先后打开了cloudDriver和alist alist各云盘工作正常 但是cloudDriver挂载居然掉了??我踏马 :@(吐血倒地) 我怎么就不先去网盘挂载点看看资源还能不能读取 于是乎重新挂上 再去filestation里看 嗯??怎么文件还是没有 然后我又回去排查 挂载没问题 但是挂载路径不对啊 我挂到了另一个盘上 地址不对之前视频是怎么刮得屑? :@(吐血倒地) 一通操作改完了 顺便还去检查了下各盘符文件夹权限问题 都已经配置 回到emby 妈蛋这就好使了= = 总结来说 这个问题是cloudDriver掉挂载的问题 但是不知道为啥 挂载路径会突然变成另一个(难道是因为浏览器自动填写的问题?我当时挂的时候也没在意) 总之 遇到emby不能播放视频 首先检查一下1权限是否给到 2网盘 token是否正常 3 alist clouddriver挂载是否正常 4 最后一步再去看解码问题 一般你配置好了解码 除非一些很奇葩的格式没法解码 正常常见格式是没有问题的
2023年12月07日
89
0
0
2023-12-01
关于服务器配置反代隐藏端口中遇到的问题
最近双十一,本人一直在关注着便宜的vps想捡个漏 :@(高兴) 没成想还真让我找到了 这里不是广告啊 人家也没给我推荐费 是我同事推荐给我的 我是用了这是第三天了 感觉还不错 挺稳定的 咱不追求时延啊 上传下载峰值是不是稳定啊 cpu性能是不是虚标啊(还没到那一步) 就是想把群晖这个该死的带端口访问这个难为了强迫症患者的我3年的心头之痛给解决掉 于是乎 图省事直接装的宝塔 一顿nginx配置 算是把各个项目能访问到了 :@(赞一个) :@(赞一个) :@(赞一个) 这仅仅是第一步 我就感觉没这么轻松就解决掉的 今天我又挨个服务去测试了一下 果然 新的风暴又出现了(我他妈真想停滞不前 :@(吐血倒地) ) webstation起的项目比方说 typecho 首当其冲网站是可以访问的 资源加载都好注意要修改这里的配置 think: 不设置这 php读取的地址有部分静态资源(应该不是缓存问题)还是会访问你群晖的域名+typecho端口 这样就会报跨域问题 think: 同时需要注意下你用的主题是否存在静态资源的指定地址 我是markdown中的表情和部分> 功能没法使用 expression.json资源请求cros问题 (ps:我是因为之前Joe大神发布> 的1.2的版本里 Joe大自己封装的markdown编辑器需要访问cdn资源,但是这个cdn资源> 很薛定谔,时灵时不灵,所以干脆直接就下下来放到我的群晖上,速度快还方便,这里是我> 疏忽了,忘了资源是我自己的了 :@(喷血) ) 这样typecho问题得到了暂时的解决= =还不知道后续会不会出现问题接下来是 chevereto V4这个小浪蹄子 (我特么真实无福消受啊 :@(愤怒) :@(愤怒))这个是不完全解决方案 能力有限 可能要涉及改php代码 但是我是真看不懂chevereto代码 太沉了 不说了说多了都是泪说一下我的方法 去到chevereto V4的根目录 找到这个文件放开图中所示的三行代码 think: CORS header (avoids font rendering issues) 这注释写的很明白 避免字体渲染问题 需要配置上二级域名和webstation的项目地址 > > 这样就可以指定二级域名跨域了(我是没写正则 直接写死的 如> 果有别的多二级域名的> > 需> 求建议自己写正则来匹配) think: woff2不再报错但是相应的点击网站的按钮 登录或者探索等 还是会跳到群晖的webstation的项目地址 就很烦 think: 这种方法也不行= =整不会 等之后我细看看代码逻辑看能不能改一改 求php大神救命!接下来是群晖的 Synology Photos相应的note file video 设置了别名的门户d都可以这么设置这个牵扯到反代服务器的nginx设置 我一并贴出来 # http(80) -> https(443/ssl) server { listen 80; server_name *.snowlove.top; rewrite ^(.*)$ https://$host$request_uri; } # 单独配置图床服务器 server{ listen 443 ssl; server_name image.snowlove.top; gzip_static on; ssl_certificate #填写你的ssl cer; ssl_certificate_key #填写你的ssl key; # 配置websocket proxy_connect_timeout 4s; proxy_read_timeout 60s; #如果没效,可以考虑这个时间配置长一点 proxy_send_timeout 12s; #升级http1.1到 websocket协议 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; location / { proxy_pass #chevereto地址; } server{ listen 443 ssl; server_name *.snowlove.top; gzip_static on; ssl_certificate #填写你的ssl cer; ssl_certificate_key #填写你的ssl key; # 配置websocket proxy_connect_timeout 4s; proxy_read_timeout 60s; #如果没效,可以考虑这个时间配置长一点 proxy_send_timeout 12s; #升级http1.1到 websocket协议 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; #以上三行,目的是将代理服务器收到的用户的信息传到真实服务器上 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #正则表达式 配置二级域名反代 if ($http_host ~* "^(.*?)\.snowlove\.top$") { set $domain $1; #设置变量 } location / { # photo if ($domain ~* "photo") { # 此处进行重写地址 rewrite ^/(.*)$ /photo/$1 break; proxy_pass #群晖地址:5001; } # ... more proxy_pass #群晖地址:404; } } think: 目前测试上传正常 图片正常今天忙忙活活一天就弄了这几个破问题 属实是脑袋瓜子嗡嗡的 剩下的应用明天继续测试 可能还会遇到更新的风暴 :@(尴尬) :@(尴尬) :@(尴尬) 想想就觉着难受= =之后的测试会陆续补上今天就到这叭 下班回家!!!续:2023-12-03 19:52:53 星期日我又来了同志们 :@(脸红) :@(脸红) :@(脸红) 继周五脑瓜子嗡嗡了一天 周天我的脑袋强烈要求我不要停 加大力度! :@(中指) :@(中指) :@(中指)接下来是 codepen这次的项目是github上找到的一个还是比较实用的运行片段代码的项目 通过简单的访问就发现了一个问题 里面的js css网络通但是返回内容都是index.html内容对于我这个nginx新手 我的理解很简单 proxy_pass https://服务器域名; 配置了转发了就完事了 但是好像情况并不如此盲目没有目的的瘦了一圈无果 我就又看了看js的返回内容 想到了 是不是在群晖docker中起的nginx配置有问题没错 没用webstation起 直接down的项目build了一下 放在了一个nginx中 打算的是把这种编译后的项目统一用一个nginx管理起来 location /codepen/ { add_header Access-Control-Allow-Origin *; autoindex on; root /etc/nginx/html; # 前端代码dist文件所在磁盘目录位置 index index.html index.htm; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # index index.html index.html; # dist文件夹中的入口文件index.html try_files $uri $uri/ /codepen/index.html; } think: 是不是因为就因为没有找到js资源 走了try_files于是我尝尝试添加了一条 location ~* ^/codepen/(.*)$ { proxy_pass https://群晖地址:xxxx/codepen/$1; break; }问题解决 :@(赞一个)
2023年12月01日
104
0
0
2023-11-15
fetch封装
/** * @Author : Xiao Xiang Lun * @Date : 2023-11-15 15:57:06 * @LastEditors : snowlove xiaoxl@botech.com.cn * @LastEditTime : 2023-11-15 16:31:45 * @FilePath : /react/demo/src/views/DemoStoreTwo/fetchReq.js * @Environment : mac node v16.3.0 * @Description : * @关注作者请访问 https://snowlove.synology.me:5 * @备用地址:https://nas.snowlove.top:5 */ /* http([config]) + url 请求地址 + method 请求方式 *GET/DELETE/HEAD/OPTIONS/POST/PUT/PATCH + credentials 携带资源凭证 *include/same-origin/omit + headers:null 自定义的请求头信息「格式必须是纯粹对象」 + body:null 请求主体信息「只针对于POST系列请求,根据当前服务器要求,如果用户传递的是一个纯粹对象,我们需要把其变为urlencoded格式字符串(设定请求头中的Content-Type)...」 + params:null 设定问号传参信息「格式必须是纯粹对象,我们在内部把其拼接到url的末尾」 + responseType 预设服务器返回结果的读取方式 *json/text/arrayBuffer/blob + signal 中断请求的信号 ----- */ // import qs from 'https://cdn.bootcdn.net/ajax/libs/qs/6.11.2/qs.min.js'; const class2type = , toString = class2type.toString, hasOwn = class2type.hasOwnProperty, isPlainObject = function isPlainObject(obj) { let proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") return false; proto = Object.getPrototypeOf(obj); if (!proto) return true; Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && Ctor === Object; }, qsStringify = function qsStringify(obj) { const params = []; for (const key in obj) { if (obj.hasOwnProperty(key)) { const value = obj[key]; const encodedKey = encodeURIComponent(key); const encodedValue = encodeURIComponent(value); params.push(`$=$`); } } return params.join('&'); } /* 核心方法 */ const http = function http(config) { if (!isPlainObject(config)) config = ; const controller = new AbortController(); config = Object.assign({ url: '', method: 'GET', credentials: 'include', headers: null, body: null, params: null, responseType: 'json', signal: (controller && controller.signal) || null, }, config); if(config.abort || config.abort instanceof Promise) { config.abort().then((_)=>controller.abort()) } if (!config.url) throw new TypeError('url must be required'); if (!isPlainObject(config.headers)) config.headers = ; if (config.params !== null && !isPlainObject(config.params)) config.params = null; let = config; // 处理问号传参 if (params) { url += `$$`; } // 处理请求主体信息:按照我们后台要求,如果传递的是一个普通对象,我们要把其设置为urlencoded格式「设置请求头」? if (isPlainObject(body)) { body = qsStringify(body); headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // 发送请求 method = method.toUpperCase(); config = { method, credentials, headers, cache: 'no-cache', signal }; if (/^(POST|PUT|PATCH)$/i.test(method) && body) config.body = body; return fetch(url, config) .then(response => { let = response; if (/^(2|3)\d$/.test(status)) { // 请求成功:根据预设的方式,获取需要的值 let result; switch (responseType.toLowerCase()) { case 'text': result = response.text(); break; case 'arraybuffer': result = response.arrayBuffer(); break; case 'blob': result = response.blob(); break; default: result = response.json(); } return result; } // 请求失败:HTTP状态码失败 return Promise.reject({ code: -100, status, statusText }); }) .catch(reason => { return Promise.reject(reason); //统一处理完提示后,在组件中获取到的依然还是失败 }); }; /* 快捷方法 */ ["GET", "HEAD", "DELETE", "OPTIONS"].forEach(item => { http[item.toLowerCase()] = function (url, config) { if (!isPlainObject(config)) config = ; config['url'] = url; config['method'] = item; return http(config); }; }); ["POST", "PUT", "PATCH"].forEach(item => { http[item.toLowerCase()] = function (url, body, config) { if (!isPlainObject(config)) config = ; config['url'] = url; config['method'] = item; config['body'] = body; return http(config); }; }); export default http;调用方法 如需中断链接 传入abort回调 在其中重写逻辑 注意返回一个promisehttp.get(' https://snowlove.synology.me:6002/mock/6553259ddb7e05001d99be09/example/query',{ abort:()=>new Promise((reslove)=>{ console.log("abort1") reslove(true) }) }).then(res=>{ console.log(res) }).catch(err=>{ console.log("捕捉主动终止错误") }) http.get(' https://snowlove.synology.me:6002/mock/6553259ddb7e05001d99be09/example/query',{ abort:()=>new Promise((reslove)=>{ console.log("abort2") setTimeout(() => { reslove(true) }, 1000); }) }).then(res=>{ console.log(res) }).catch(err=>{ console.log("捕捉错误2") }) /** * abort1 * abort2 * 捕捉错误 */
2023年11月15日
15
0
0
2023-11-02
二次封装省市区组件
最新正在搭一个系统,用的h5纯原生开发的就没使用框架 也不想引用现成的ui框架 踌躇满志 :@(坐等) 磨拳擦掌 :@(欢呼) 力排众议 :@(深思) 直接选择自己手写 然后完犊子了 :@(脸红) :@(脸红) :@(脸红) 工期赶任务中 有思路知道怎么实现但是这个手啊就是敲不下去 遂又 垂头丧气 :@(小怒) 不自量力 :@(吐血倒地) 唯唯诺诺 :@(喜极而泣) 的光速打脸 遇到下拉框联动省市区的时候傻眼了麻爪了 网上一顿搜 没有合适的组件库 一度想要引入element然后直接vue完事了 但是最终还是选择了multiple-select.js 不过这个库依赖jquery 退而求其次 那就原生 jquery混写呗 下面是代码 处理过的省市区数据CITY_CODE.js<link rel="stylesheet" href="https://unpkg.com/multiple-select@1.6.0/dist/multiple-select.min.css"> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script src="https://unpkg.com/multiple-select@1.6.0/dist/multiple-select.min.js"></script> <script src="https://snowlove.synology.me:5106/usr/uploads/2023/11/1528140937.js"></script> <style> .city-code_wapper.city-code_wapper_citycode .multiple-select.city-code_wapper_citycode .multiple-select:last-child.city-code_wapper_citycode button.city-code_wapper_citycode button span.city-code_wapper_address.city-code_wapper_address label.city-code_wapper_address input.city-code_wapper .area,.city-code_wapper .city.city-code_wapper .ms-drop.from_input.from_input:focus </style> <div class="city-code_wapper"> <div class="city-code_wapper_citycode"> <select class="province multiple-select" placeholder="省"></select> <select class="city multiple-select" placeholder="市"> <option>市</option> </select> <select class="area multiple-select" placeholder="区"> <option>区</option> </select> </div> <div class="city-code_wapper_address"> <label>详细地址:</label> <input type="text"class="from_input detailed-address" name="address"/> </div> </div> <script> // 模板解析有问题 无发放到template中 只能抽出js单独引入 var selectParams = [] // 根据parentId获取所有子元素 const getDataByParentId = (data,parentId) => { return data.filter(item => item.parentId === parentId) } // 设置省市区数据 const updateCityCodeData = () => { window.postMessage({ type:'cityCodeMsg', newCityCode:selectParams.map(item=>item.text || item), cityCodeOriginal:selectParams }) } // 清空省市下拉数据 const clearCityOrArea = (type) => { const cityEle = $('.city'), areaEle = $('.area'), addressEle = $('.detailed-address') switch (type) { case 'city': cityEle.multipleSelect('refreshOptions', { data:[] }) break; case 'area': areaEle.multipleSelect('refreshOptions', { data:[] }) break; case 'address': addressEle.val('') break; default: cityEle.multipleSelect('refreshOptions', { data:[] }) areaEle.multipleSelect('refreshOptions', { data:[] }) addressEle.val('') break; } } // 加载jqery 多选框元素 $(function() { const provinceEle = $('.province') let initFlag = [1,0,0] provinceEle.multipleSelect({ selectAll: false, name:'province', data:Province, placeholder:'省', showClear:true, onClick: function (province) { // 清空市区数据 const cityEle = $('.city') if(!initFlag[1]){ cityEle.multipleSelect({ selectAll: false, name:'city', placeholder:'市', data:getDataByParentId(City,province.value), onClick: function (city) { const areaEle = $('.area') // console.log('areaEle',areaEle) if(!initFlag[2]){ areaEle.multipleSelect({ selectAll: false, name:'area', placeholder:'区', data:getDataByParentId(Area,city.value), onClick: function (area) { // console.log('areaEle onClick',areaEle) selectParams[2] = area updateCityCodeData() }, }) initFlag[2] = 1 } else areaEle.multipleSelect('refreshOptions', { data:getDataByParentId(Area,city.value), }) // console.log('areaEle',areaEle) selectParams[1] = city clearCityOrArea('address') updateCityCodeData() }, }) initFlag[1] = 1 } else cityEle.multipleSelect('refreshOptions', { data:getDataByParentId(City,province.value), }) selectParams = [province] if(initFlag[2]) clearCityOrArea('area') clearCityOrArea('address') // 发送消息到上层 清空已选择数据 updateCityCodeData() }, onClear: function () { selectParams = [] if(initFlag[1]) clearCityOrArea('city') if(initFlag[2]) clearCityOrArea('area') clearCityOrArea('address') updateCityCodeData() // console.log('clear') } }) // 每次组件创建 初始化数据 provinceEle.multipleSelect('setSelects', []) updateCityCodeData() // 获取详细地址 $('.detailed-address').blur(function(){ selectParams[3] = $(this).val() || '' updateCityCodeData() }) }) </script> .city-code_wapper.city-code_wapper_citycode .multiple-select.city-code_wapper_citycode .multiple-select:last-child.city-code_wapper_citycode button.city-code_wapper_citycode button span.city-code_wapper_address.city-code_wapper_address label.city-code_wapper_address input.city-code_wapper .area,.city-code_wapper .city.city-code_wapper .ms-drop .from_input{ width: 100%; border: 1px solid #c8c9cc; border-radius: 4px; padding: 5px 10px; box-sizing: border-box; outline: none; /* 去掉描边 */ color: #606266; } .from_input:focus { color: #303133; } 市 区 详细地址: // 模板解析有问题 无发放到template中 只能抽出js单独引入 var selectParams = [] // 根据parentId获取所有子元素 const getDataByParentId = (data,parentId) => { return data.filter(item => item.parentId === parentId) } // 设置省市区数据 const updateCityCodeData = () => { window.postMessage({ type:'cityCodeMsg', newCityCode:selectParams.map(item=>item.text || item), cityCodeOriginal:selectParams }) } // 清空省市下拉数据 const clearCityOrArea = (type) => { const cityEle = $('.city'), areaEle = $('.area'), addressEle = $('.detailed-address') switch (type) { case 'city': cityEle.multipleSelect('refreshOptions', { data:[] }) break; case 'area': areaEle.multipleSelect('refreshOptions', { data:[] }) break; case 'address': addressEle.val('') break; default: cityEle.multipleSelect('refreshOptions', { data:[] }) areaEle.multipleSelect('refreshOptions', { data:[] }) addressEle.val('') break; } } // 加载jqery 多选框元素 $(function() { const provinceEle = $('.province') let initFlag = [1,0,0] provinceEle.multipleSelect({ selectAll: false, name:'province', data:Province, placeholder:'省', showClear:true, onClick: function (province) { // 清空市区数据 const cityEle = $('.city') if(!initFlag[1]){ cityEle.multipleSelect({ selectAll: false, name:'city', placeholder:'市', data:getDataByParentId(City,province.value), onClick: function (city) { const areaEle = $('.area') // console.log('areaEle',areaEle) if(!initFlag[2]){ areaEle.multipleSelect({ selectAll: false, name:'area', placeholder:'区', data:getDataByParentId(Area,city.value), onClick: function (area) { // console.log('areaEle onClick',areaEle) selectParams[2] = area updateCityCodeData() }, }) initFlag[2] = 1 } else areaEle.multipleSelect('refreshOptions', { data:getDataByParentId(Area,city.value), }) // console.log('areaEle',areaEle) selectParams[1] = city clearCityOrArea('address') updateCityCodeData() }, }) initFlag[1] = 1 } else cityEle.multipleSelect('refreshOptions', { data:getDataByParentId(City,province.value), }) selectParams = [province] if(initFlag[2]) clearCityOrArea('area') clearCityOrArea('address') // 发送消息到上层 清空已选择数据 updateCityCodeData() }, onClear: function () { selectParams = [] if(initFlag[1]) clearCityOrArea('city') if(initFlag[2]) clearCityOrArea('area') clearCityOrArea('address') updateCityCodeData() // console.log('clear') } }) // 每次组件创建 初始化数据 provinceEle.multipleSelect('setSelects', []) updateCityCodeData() // 获取详细地址 $('.detailed-address').blur(function(){ selectParams[3] = $(this).val() || '' updateCityCodeData() }) })
2023年11月02日
16
0
0
1
2
3
...
13