首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
320 阅读
2
如何在 Clash for Windows 上配置服务
215 阅读
3
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
150 阅读
4
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
149 阅读
5
uniapp打包app提示通讯录权限问题,如何取消通讯录权限
113 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,195
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
758
篇与
的结果
2024-10-21
CSS中margin出现空白的问题
我们写了这么多的CSS,也多少了解了margin的一些特性,比如: 水平边距永远不会重合。 垂直边距可能在特定的框之间重合: 常规流向中两个或多个块框相邻的垂直边距会重合。结果的边距宽度是相邻边距宽度中较大的值。如果出现负边距,则在最大的正边距中减去绝对值最大的负边距。如果没有正边距,则从零中减去绝对值最大的负边距。 在一个浮动框和其它框之间的垂直边距不重合。 “绝对定位的框”与“相对定位的框”边距不重合。 不过这里我们要说的当前元素的margin与其父级元素之间产生的效果。我们以这个DOM结构来举例,.container为最外层的父级元素:*{margin: 0; padding: 0;} .container{background-color: #d8bea5;} .user{background: #8bce92;} .user .b1{margin-top: 20px;} 123 我们先看下上边距的情况,在 .user, .a1, .b1中,无论哪个元素,只要其父级元素没有设置padding-top或者没有其他元素(元素节点或者文本)的输出,那么当前元素的顶部会与其父级元素的顶部对齐,margin-top的边距就会上升到其父级;然后一直向上寻找,直到body元素。比如上面的结构中,我们给.b1一个margin-top值,最终会上边距会给到了.container如果我们只想给当前元素一个人margin-top值,并不想影响其父级元素怎么办呢? 给其直接父元素一个不为零的padding-top值; 给当前元素的前面添加一个高度不为零的兄弟元素,这个兄弟元素可以用visibility:hidden占位隐藏,但不能用display:none隐藏,因为dispplay:none会使这个元素的高度变为0; 给父元素一个透明的边线: border:1px solid transparent; 将父元素设置为绝对定位 position:absolute; 父元素添加 overflow:hidden; 最后就是考虑是否将margin-top切换成padding-top。 再一个就是下边距的问题,下边距会与上边距产生一模一样的问题,也可以按照这3种方式来解决。不过这里的下边距还有另外一个问题。我们使用这条语句,将.container的最小高度设置为页面的高度:function resize(){ document.querySelector('.container').style.minHeight= document.documentElement.clientHeight + "px"; } resize(); 我们再给.user或.a1或.b1一个margin-bottom值,我们会发现,在.user的高度+下边距还远远没有超过.container的高度时,页面就已经产生滚动条了,说明margin-bottom已经作用到.container了。之前没注意到这个现象,是我们的产品在用之前的页面修改后作为新页面的时候,发现产生了滚动条,调试后才发现,原来是里面的一个元素有margin-bottom把整个页面撑开了,造成页面产生了滚动条,底部有一部分的白底。这个怎么解决呢,解决方法依然同上!
2024年10月21日
14 阅读
0 评论
0 点赞
2024-10-21
Vue中对数组特殊的操作
1. 为什么 Vue 中不能通过索引来修改数组以更新视图 # 我们知道在 Vue 中的数据是通过Object.defineProperty这种劫持的方式来实现数据更新的,可是数组是一个比较特殊的类型。官网上说: 由于 JavaScript 的限制,Vue 不能检测以下变动的数组: 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength 我搜寻其他的文章里也说是因为大部分浏览器Object.observe()支持的不友好,不能检测很好的检测到数组的数据变化,因此在 Vue 中则使用了其他的方法来实现数据的更新。那么我就在想,作者为什么不用 Object.defineProperty 来实现对数组的数据劫持呢,不能实现的原因是什么呢?我们这里来看个 demo:function defArray(obj, key, val) { Object.defineProperty(obj, key, { get() { console.log('get val: ' + val); return val; }, set(newVal) { console.log('old value: ' + val); console.log('new value: ' + newVal); val = newVal; }, }); } let arr = [0, 1, 2, 3, 4, 5]; arr.forEach((item, index) => { defArray(arr, index, item); }); arr[1] = 123; // 修改索引为1的值 /* > arr[1] = 1 old value: 1 new value: 123 123 */ console.log(arr[2]); // 获取索引为1的数据 /* > console.log(arr[2]); get val: 2 2 */ arr 数组的长度为 6,修改索引在 0-5 之间任意索引的数据,都能触发 set 方法,获取相应的数据时,就能触发 get 方法。不过当获取额外的数据时,或者先删除原数据再添加时,就不会触发相应的方法了:arr[6] = 6; console.log(arr[6]); // 6 delete arr[2]; arr[2] = 2; console.log(arr[2]); 因为上面我们只对已存在的索引的数据进行数据劫持,新添加的数据或者先删除再添加的数据,都是没有 get 和 set 方法的,都不能通过数据劫持的方式来更新视图。但数组是正常更新的,只是无法更新视图了。所以我在这里大胆的猜测一下作者不用索引来更新视图的原因:防止因新添加或者先删除再添加等的操作,导致后续添加的数据没有 get 和 set 方法,在 Vue 中就统一操作,无论是数组还是 Object 类型的数据,都可以通过Vue.$set(Array|Object, key, val)来操作数据,并更新视图(当然,Object 类型的数据,在 Vue 初始化时就已经存在的 key,是可以直接通过 key 来修改的哈)。作者尤雨溪在 GitHub 上有专门的回复,为什么 vue 没有提供对数组属性的监听: 因为性能问题,性能代价和获得的用户体验收益不成正比。 以下源码均摘自与 github 上的Vue.js v2.5.17-beta.0版本。 commit 链接: Vue.js v2.5.17-beta.0 2. 变异方法更新数组 # 在官方网站中,提供了以下几个方法来检测数组的变化,也会触发视图的更新: push() pop() shift() unshift() splice() sort() reverse() 在 Vue 的源码中,对 Vue 中的数组数据实现了类似的方法,这里官方的叫法是变异方法,比如push()方法,并不是调用 Array 中原生的 push 方法,而是调用自己实现的 push 方法,来实现数据的劫持,再通过 Array 中的 push 方法实现数组数据的更新,可能有点晕,看代码,我这里把几个距离较远的代码都放到一块了,但代码都没动,只是改了位置:// 获取原生Array中提供的所有方法 var arrayProto = Array.prototype; // 将原生提供的方法创建一个新的对象,以免修改原生的方法,造成全局污染 var arrayMethods = Object.create(arrayProto); // 将要实现的几个变异方法 var methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; /** * Intercept mutating methods and emit events * 截取这些方法,然后实现相应的操作 */ methodsToPatch.forEach(function (method) { // cache original method var original = arrayProto[method]; // 缓存原始方法 // def即Object.defineProperty的包装函数 def(arrayMethods, method, function mutator() { var args = [], len = arguments.length; while (len--) args[len] = arguments[len]; var result = original.apply(this, args); // 调用原始方法完成对数组的更新 var ob = this.__ob__; var inserted; // 存储要修改的数据 switch (method) { case 'push': case 'unshift': inserted = args; break; case 'splice': inserted = args.slice(2); break; } console.log(args, inserted); if (inserted) { ob.observeArray(inserted); } // 如果有修改的数据,则添加observer监听器 // notify change ob.dep.notify(); // 触发更新 return result; }); }); /** * Observe a list of Array items. * 对数组中的每项添加监听器 */ Observer.prototype.observeArray = function observeArray(items) { for (var i = 0, l = items.length; i < l; i++) { observe(items[i]); } }; 这里我们也就知道了,在 Vue 中的数组数据,调用上面的那些方法,都是事先实现的同名方法,然后再通过apply调用原生方法,再添加监听器,触发更新等后续操作。如果我们自己想单独实现下这样的操作如何实现呢,如果把仅仅把上面的代码拿出来是不行的,这些自定义的变异方法还没有跟数组进行绑定呢,数组调用这些方法时,还是原生的方法,因此这里我们需要把这些变异方法绑定到数组上,我们来看下 Vue 源码中的实现:// can we use __proto__? var hasProto = '__proto__' in {}; // __proto__是否可用 /** * Observer class that is attached to each observed * object. Once attached, the observer converts the target * object's property keys into getter/setters that * collect dependencies and dispatch updates. */ var Observer = function Observer(value) { this.value = value; this.dep = new Dep(); this.vmCount = 0; def(value, '__ob__', this); if (Array.isArray(value)) { // 当前数据为数组,若__protp__可用,则调用protoAugment方法,否则调用copyAugment方法 var augment = hasProto ? protoAugment : copyAugment; augment(value, arrayMethods, arrayKeys); this.observeArray(value); // 监听数组的每一项 } else { this.walk(value); } }; /** * Augment an target Object or Array by intercepting * the prototype chain using __proto__ * 把这些方法定义到原型链__proto__上 */ function protoAugment(target, src, keys) { /* eslint-disable no-proto */ target.__proto__ = src; /* eslint-enable no-proto */ } /** * Augment an target Object or Array by defining * hidden properties. * ie9、ie10 和 opera 没有 __proto__ 属性,为数组添加自定义方法 */ /* istanbul ignore next */ function copyAugment(target, src, keys) { for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i]; def(target, key, src[key]); } } 这样就能给每个数组添加上这些变异方法了。因此 Vue 中也可以使用splice()来更新数组中的内容:vm.$arr.splice(index, 1, newVal); 我们自己实现这样的操作时,可以把上面的 Observer 简化一下:function init(value) { // can we use __proto__? var hasProto = '__proto__' in {}; var augment = hasProto ? protoAugment : copyAugment; augment(value, arrayMethods, arrayKeys); } var arr = [1, 2, 3, 4, 5]; init(arr); arr.splice(2, 1, 2); arr.push(6, 7, 8); 3. Vue.$set 的实现 # 不多说话,直接看源码怎么实现的,内部有本人的中文注释:/** * Set a property on an object. Adds the new property and * triggers change notification if the property doesn't * already exist. * 在一个对象上设置一个属性。如果该属性尚不存在,则添加新属性并触发更改通知。 */ function set(target, key, val) { if ('development' !== 'production' && (isUndef(target) || isPrimitive(target))) { warn('Cannot set reactive property on undefined, null, or primitive value: ' + target); } // 如果当前对象是数组,且key是合法的数字索引 if (Array.isArray(target) && isValidArrayIndex(key)) { // 若索引值小于数组的长度,则数组长度不变,只修改 // 若索引值比当前数组的长度大,则说明是新添加元素,需要更新数组的长度 // 这里采用变异方法splice来更新数组 target.length = Math.max(target.length, key); target.splice(key, 1, val); return val; } // 以下操作时,target均为object对象类型 // 若当前key已经存在于对象中,且没有原型链中,直接更新即可 // 因为在Vue初始化时已经添加了监听器,这里就不用再添加了 if (key in target && !(key in Object.prototype)) { target[key] = val; return val; } var ob = target.__ob__; // 若当前对象是Vue实例,则不允许使用这种方式添加属性,应当在初始化时预先声明 if (target._isVue || (ob && ob.vmCount)) { 'development' !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.', ); return val; } // ? 若当前对象没有监听器?则直接赋值?这里不太能理解 if (!ob) { target[key] = val; return val; } // 若当前key不存在,则在ob.value上创建set和get方法,并触发更新 defineReactive(ob.value, key, val); ob.dep.notify(); return val; } 因此使用 Vue.$set 方法更新数组时,内部依然是用的splice()方法来操作的,而更新对象类型的数据则略微复杂点。本人学艺不精、才疏学全,如果还有什么疏漏的地方,还望批评指正!
2024年10月21日
6 阅读
0 评论
0 点赞
2024-10-21
如何在npm上发布你的package
在自己平时工作或者学习中,总结出来的模块,我们可以将其提炼发布到npm上,这样即使有多个项目使用这个包时,也能方便地进行更新。我在把自己之前总结的模块发布到npm上时,遇到了几个问题,现在把刚才踩过的坑亮出来,方便大家能随时躲过去。 1. 使用rollup而不是webpack # 在我的模块里,只是使用几个简单的ES6语法,而且最终编译出来的代码要能在ES6, AMD, CMD中均能使用。针对这个简单的功能,就没必要使用webpack这么大的工具了,使用rollup即可,而且打包出来的额外代码还特别少。rollup的配置也很简单,我们先看下package.json引用的模块:{ "name": "tencent-downapp", "version": "0.0.4", "description": "集成了微信、QQ、腾讯视频、QQ音乐和腾讯动漫等APP的api,用来打开和下载第三方的api", "main": "dist/bundle.js", "repository": "https://github.com/wenzi0github/tencent-downapp.git", "files": [ "src", "dist/bundle.js" ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "rollup -c" }, "author": "wenzi", "license": "ISC", "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.4", "babel-plugin-external-helpers": "^6.22.0", "babel-polyfill": "^6.26.0", "babel-preset-env": "^1.7.0", "rollup-plugin-babel": "^3.0.5", "rollup-plugin-node-resolve": "^3.3.0" } } rollup.config.js的配置内容:import resolve from 'rollup-plugin-node-resolve'; import babel from 'rollup-plugin-babel'; const config = require( './package' ); const banner = '/*!\n' + ' * AppDownload v' + config.version + '\n' + ' * last update: ' + (new Date()).toLocaleDateString() + ', author: skeetershi\n' + ' * Released under the MIT License.\n' + ' */' export default { entry: './src/index.js', plugins: [ resolve(), babel({ exclude: './node_modules/**', plugins: ['external-helpers'] }) ], output: { file: './dist/bundle.js', format: 'umd' }, banner }; 这样就行了,执行npm run build后,就能在dist目录中看到编译后的文件。 2. 发布时忽略的内容 # 发布到npm上的包,默认是不上传node_modules文件夹中的内容的。同时呢,你还可以创建一个.npmignore文件,来确定更多的忽略文件和文件夹。 如果你的模块里还有.gitignore文件时,同样也会忽略这里面包含的文件和文件夹。所以,通常编译后产生的目录(我这里的是dist目录),我们是不加入git追踪的,把dist目录添加到.gitignore中。可是这样也就上传不到npm上了,我们就需要在package.json中,添加一个files数组字段:{ "files":[ "dist" ] } 这样就能把dist目录中所有的文件内容都发布到npm上。当然,这里也可以写成单独的文件:{ "files": [ "dist/bundle.js", "dist/bundle.min.js", "dist/bundle.esm.js" ] } 3. 引用时,引用的是哪个文件 # 刚开始我有这样的一个疑惑,模块里这么多文件,当install完成后,require或者import文件夹时,用的是哪个文件呢,这里就需要在package.json中指定好即可:{ "main": "dist/bundle.js" }
2024年10月21日
6 阅读
0 评论
0 点赞
2024-10-21
单页面应用中js获取url中的参数
在很久之前写过一篇文章【javascript获取URL链接和js链接中的参数】,在那篇文章里我们讲解了如何直接获取当前页面链接中的参数,和修改后获取任意url的参数。不过在最近的需求里,之前文章里的知识已经无法满足了。现在我们是基于Vue开发的单页面应用,单页面应用里是使用#hash进行路由切换的,那么现在的问题是: 无论之前的URL有没有带参数,都会在最后加上#。比如从其他链接跳转过来时带有参数,页面的URL就会变成这样:http://www.xxx.com/?a=1&b=2#/ 如果从主页再往二级页跳转时还带有参数,页面的URL就会成这样:http://www.xxx.com/?a=1&b=2#/user?uname=蚊子&year=2018 在这个具有两个?的链接,location.search获取到的是哪个值?测试一下我们就会发现,获取到的是前面?到#之前的参数:console.log( location.search ); // "?a=1&b=2" 因此这里我们需要对整个url进行检索,这样hash#前后的数据就都能获取到了:function getQueryString(name) { var reg = new RegExp("[?&]" + name + "=([^]*)", "i"); var res = window.location.href.match(reg); if( res && res.length>1 ){ return decodeURIComponent(res[1]); } return ''; } getQueryString('a'); // "1" getQueryString('b'); // "2" getQueryString('uname'); // "蚊子" getQueryString('year'); // "2018" 到这里这个功能已经完工了。不过在我们项目的具体实施中,还有一个特殊的需求: 有的参数会以json string格式放在某个字段里传递进来,然后页面再获取到这个字段后进行JSON.parse转换,最后才能获取到json中的值。之前是每次getQueryString('extra')获取到数据后,再进行json解析,而且为了防止json解析错误,还都要加上try...catch。因此,我也把这个特殊的需求融入到了这个函数里,过程也非常简单,就是多了一步额外的检测:// name: 要获取的字段 // extra json string存放的字段 function getQueryString(name, extra='extra') { var get = function(_name){ var reg = new RegExp("[?&]" + _name + "=([^]*)", "i"); var res = window.location.href.match(reg); if( res && res.length>1 ){ return decodeURIComponent(res[1]); } return ''; } var res = get(name); // 若存在参数则直接返回 if( res ){ return res; } // 若不存在,则检测需要的参数是否包含在extra中 let _addparams = get(extra); if( _addparams ){ try{ let info = JSON.parse(_addparams); return info[name]; }catch(e){ } } return ''; } 这样在项目的其他地方直接使用即可,不用再考虑name字段具体在哪个位置。
2024年10月21日
11 阅读
0 评论
0 点赞
2024-10-21
实现了几个基于腾讯新闻客户端的h5前端基础组件
在平时工作中做了不少基于新闻客户端的需求,在这些工作中,对其进行汇总提取,形成了这些npm基础组件。有什么不足的地方也希望大家能多多提意见。 tencent-downapp 在微信、QQ、浏览器等中打开或者下载指定APP tencent-share 设置h5在微信、QQ、腾讯新闻客户端、腾讯视频的分享信息(标题、描述、图片和链接); tencent-update 可用户上报一些前端用户数据; tencent-qqnews-user 在腾讯新闻客户端中进行登录、获取用户信息和提交请求等操作 tencent-downapp # npm install tencent-downapp --save-dev 该模块主要用于在外部呼起app时使用,配置好参数后,执行run()方法即可执行打开或者下载操作:import AppDownload from 'tencent-downapp'; var downapp = new AppDownload({ openUrl: 'qqnews://article_9527?nm=RSS2018061501588400', packageName: 'com.tencent.news', downloadUrl: 'http://dldir1.qq.com/dlomg/inews/channel/TencentNews_3932.apk', wxhash: '1cbd02bbed81c8a5b990044e9f844eda', // 微信中下载完成时是需要进行hash校验的,并且每次发版,hash值都会变动 appleStoreId: '399363156', appName: '腾讯新闻--百万现金红包派发中...', downLogo: 'http://mat1.gtimg.com/news/news/logo.png' }); // 获取APP的安装状态 downapp.checkAppIsInstalled(function(status){ if( status ){ alert( '已安装' ); }else{ alert( '未安装' ); } }); document.querySelector('.btn').addEventListener('click', function(){ downapp.run(true); // 无视wifi }) 更详细介绍,请查看: https://www.npmjs.com/package/tencent-downapp; tencent-share # 该模块集成了微信、QQ、腾讯新闻客户端、腾讯视频客户端的分享API,可以设置分享的标题、描述、图片和链接。npm地址: https://www.npmjs.com/package/tencent-share;npm install tencent-share --save-dev 使用方式:import Share from 'tencent-share'; // 分享信息 var shareData = { title: '读腾讯新闻,助力公益事业,让你的时间更有意义', desc: '上腾讯新闻,捐阅读时长做公益,一起为爱聚力', img: 'http://mat1.gtimg.com/news/qqnews/qqspring/img/logo.png', link: window.location.href }; Share.setShareInfo(shareData); Share.setShareInWx(shareData, 'friends'); setShareInfo为总方法,调用该方法后,开发者无需关心当前处于什么环境,模块会自动根据UA设置微信、QQ、腾讯新闻客户端、腾讯视频客户端的分享信息。如果想在不同的环境里设置的信息,下面的这几个方法可以调用: setShareInWx(shareData, type) : 设置页面在微信中的分享信息,type字段稍后讲解; setShareInQQ(shareData) : 设置页面在QQ中的分享信息; setShareInNews(shareData) : 设置页面在新闻客户端中的分享信息; setShareInVideo(shareData) : 设置页面在腾讯视频中的分享信息; 在设置页面在微信中的分享信息的方法里,有个type字段,这个type字段能设置在微信中分别分享给好友、朋友圈、QQ和QQ空间的信息。setShareInWx(shareData, 'friends')表示分享给好友时的分享信息,type字段有: friends : 分享给好友 timeline : 分享到朋友圈 qq : 分享给QQ好友 qzone : 分享到QQ空间 如果没有分别设置分享信息的需求,直接调用Share.setShareInfo(shareData);即可。在新闻客户端内设置分享信息后,还可以调用show()方法来主动呼起分享面板:Share.show(); // 该方法只在新闻客户度内有效 同时,还可以在 Android版的新闻客户端 内,禁止该页面的分享功能:Share.forbidShareInNews(); tencent-updata # 该模块是前端上报数据时使用,封装了几个方法,上传数据时调用即可。npm地址: https://www.npmjs.com/package/tencent-updatanpm install tencent-updata --save-dev 简单的使用样例:import wzPing from 'tencent-updata'; var wzp = new wzPing({ user: 123456, pwd: 123456 }); wzp.ready([ function(callback){ setTimeout(function(){ callback({ now: Date.now() }) }, 400); } ]); wzp.send({act: 'PV'}) 上面的代码基本上展示出所有的功能了。 注意: 在当前模块中,是创建一个img图片,通过请求img图片的链接,来上报PV请求等。请在使用时修改为您自己的上报地址,修改方法在文章的最后有说明。 1. 初始化 # 可以把经常要上报的字段或者数据不需要变动的字段,在初始化时就传入进去。这样在后续上报行为中,都会带上这些字段。代码内部是用data来存储这些数据的,因此初始化完成后,可以用对象直接访问该属性,并对data属性进行修改:console.log( wzp.data ); 2. ready # 在数据上报前,有些字段是需要异步获取的,在上报时需要等待该字段获取到数据后,才能上传,因此,这里设置了一个ready方法,在send()方法前先调用下ready()方法,这样在ready里获取到数据后,自动执行后面的send方法。调用方式,ready方法接收一个数组,数组的每一项都是一个函数,这个函数都需要传入一个回调方法callback,回调方法里传入异步执行完毕获取到的值,这个值需要用json格式的方式:wzp.ready([ fn(callback); ]) 使用样例:wzp.ready([ function(callback){ setTimeout(function(){ callback({ now: Date.now() }) }, 400); } ]); wzp.ready([ function(callback){ setTimeout(function(){ callback({ random: (Math.random()+'').substr(-6); }) }, 600); } ]); wzp.send({act: 'PV'}) 上面的代码中,字段now和random都是异步获取到的,代码里的send会等待这两个字段都获取到后才会执行。 3. send # 调用send()方法后就会发送数据上报请求,同时send还能接受一个json格式的参数,用户当前发送时的额外数据,不同的send上报请求之间互不影响。wzp.send({act: 'PV'}); wzp.send({page: 'main'}); // 当前请求中不存在act字段 4. sendData # 最终的数据上报请求是通过这个方法发送的,我们也可以修改这个sendData方法,来修改数据上报的方式。不过记得在send()发送请求之前进行修改:/** * @param data {key1: value1, key2: value2, key3: value3} 上报的字段与对应的数据 */ wzp.sendData = function(data){ let s = '', item; for(let key in data){ item = data[key]; if( typeof item==='object' ){ // 若上传的数据为array或者json格式的,则转换为字符串 item = JSON.stringify(item); } s += '&' + key + '=' + encodeURIComponent( data[key] ); } let img = new Image(1, 1); img.src = 'xxxx.com/updata?v=1'+s+'&_t='+Math.random(); } tencent-qqnews-user # 因新闻客户端存在iOS与Android的系统差异,导致调用客户端提供的jsapi非常不方便,这里就进行了下封装,直接调用即可。用于在腾讯新闻客户端中进行登录、获取用户信息和提交请求等操作。npm地址: https://www.npmjs.com/package/tencent-qqnews-usernpm install tencent-qqnews-user 然后在代码中引用即可:import User from 'tencent-qqnews-user'; 接下来是几个方法的使用方式。 1. 登录 # 登录的方法是login(string logintype, function callback),这里接收两个参数。第1个参数登录的方式有: qq :只有QQ登录按钮 ; weixin : 只有微信登录按钮; qqorweixin; QQ和微信按钮都有,用户可以任意选择 第2个参数是登录后的回调, true表示登录成功; false表示登录失败,比如中断登录等。样例:User.login('qqorweixin', result=>{ if(result){ alert('登录成功'); }else{ console.log( '取消登录' ); } }); 注意: 在iOS的新闻客户端中,不论用户是否已经登录,都可以使用User.login再次呼起登录;在Android的新闻客户端中,若呼起的登录方式与当前的登录态相同,则直接回调为false,不会弹出登录窗口,比如当前为QQ登录,那么再次使用qq或者qqorweixin呼起登录时,都会直接回调为false。 同时,在这两个系统的新闻客户端内,若再次呼起登录的方式,与当前的登录状态不一样,则后登录的账户会作为副账户存在,不会顶掉当前主账户的信息。 2. 退出登录 # 退出登录的方法是: User.logout(),没有参数User.logout(); // 退出登录 在iOS里则会直接退出账户,而在Android的客户端里,则会弹窗让用户确认是否退出。 3. 切换账号 # 在上面我们已经说过User.login会存在两个问题: Android下若呼起的登录方式与当前的登录态相同,则无法重新登录; iOS和Android下,若呼起的登录方式与当前的登录态不同是,则后登录的账号作为副账户存在 为了解决这两个问题,客户端还提供了切换账号的功能,其实就是: 退出当前账号(logout)+重新登录(login)。若我们使用上面两个方式的组合来让用户重新登录,iOS下没问题,但在Android下,退出账号时会首先弹窗确认,而这个弹窗确认是不会阻止后面的login进程的,login就会进入到自己的判断流程,导致login失败。这里我们使用User.changeLogin(string logintype, function callback)来切换账号,切换账号的方法是客户端提供的,虽然流程还是 退出当前账号(logout)+重新登录(login),但能正常切换。传递的参数与login相同:第1个参数登录的方式有: qq :只有QQ登录按钮 ; weixin : 只有微信登录按钮; qqorweixin; QQ和微信按钮都有,用户可以任意选择 第2个参数是登录后的回调, true表示登录成功; false表示登录失败,比如中断登录等。User.changeLogin('qq', result=>{ if( result ){ alert( '切换账号成功' ); }else{ console.log( '中断切换' ); } }); 4. 获取用户信息 # 如果想要展示用户的昵称、头像等信息,可以用User.getUserInfo接口来获取,回调的字段里包含了当前用户的登录方式、昵称、头像和openid(QQ方式登录时为其qq号):/* result = { logintype: 'qq', // 'weixin',当前的登录方式;若为空,则表示未登录;以下字段均在登录后才存在 nickname: '', // 昵称 avatar: '', // 头像 openid: '' // 微信账号的openid或者QQ账号的qq号,均以openid字段返回 }; */ User.getUserInfo(result=>{ alert( JSON.stringify(result) ); }) 5. 请求接口 # 客户端里也有提供请求接口的方法,不用额外引入ajax等模块:User.post({ url: url, // 请求地址,必传,必须明确协议 data: {a:1, b:2}, // 参数,可以为空 success: function(result){ // 请求成功时 }, error: function(error, url){ // 请求失败时 }, complete: function(error, url, result){ // 成功或失败都会执行的方法 } }) 这里内部调用的是客户端提供的方法,虽说名字是post,但在实际使用中发现,get请求和post请求都会接收到。这个方法通过客户端发起调用接口时,会自动带上客户端的信息和用户的信息(如果他已登录的话)。因此后端在接收到前端通过这种方式发送过来的请求时,可以拿到相应的设备信息和用户信息,前端无需显式的带上当前设备和当前用户的信息。这里有几个要注意的点: 请求的url必须明确是http://还是https://协议,不能自动适应页面协议;不过您可以用location.prototal来获取当前页面的协议,拼接到URL上,然后再通过post进行请求; complete方法是无论请求成功还是失败都会执行,第1个参数在请求success时为null,在请求error时有数据 同时,这里还是提供两个额外的方法,记得在post之前定义:User.postSuccess(url, result): 所有通过post请求成功的都会执行这个方法,那么可以通过这个方法来进行接口数据上报的操作;User.postError(error, url): 所有通过post请求失败的都会执行这个方法
2024年10月21日
15 阅读
0 评论
0 点赞
1
...
55
56
57
...
152