首页

使用docbox定制API文档

seo达人

使用docbox定制API文档

什么是docbox

docbox的安装

克隆项目

部署方式

docbox的编写

定制logo及UI

更换代码背景色

插入自己的logo

三列改为双列

其他定制UI



在公司实习了一个月,由于业务需要,我花了大概一周时间对docbox的安装,编写,定制化等进行了详细的研究,下面给大家分享一下我的总结

什么是docbox

Docbox是一个开源的REST API文档系统。它采用结构化的Markdown文件,并生成带有导航,固定链接的两列布局。下面是官方example图片:









docbox的安装

克隆项目

直接去官网https://github.com/tmcw/docbox,然后克隆即可。



部署方式

在使用npm命令前需要下载Node.js,npm会根据package.json配置文件中的依赖配置下载安装



接着,在/content下放入.md文件,并使用 npm run build 命令,生成一个包含所需要的js代码的bundle.js文件,同时创建一个新的index.html文件



重要的就是index.html、bundle.js、/css这三个文件和文件夹



docbox的编写

在/content下放入.md文件(markdown语法俺就不说了哈……)

对/src/custom/content.js中添加需要引入的.md文件位置和以及标题





注意: /src/custom/content.js中放入的是一级标题、二级和三级标题需要在.md文件中编写。





定制logo及UI

修改/src/custom/index.js文件

修改对应标签的属性即可,定制时修改生成的index.html是没有用的,因为index.html里的标签是被动态写死的。

更换代码背景色

<div class='round-left pad0y pad1x fill-green code small endpoint-method'>

1





<div class='endpoint dark fill-blue round '>

1





插入自己的logo





修改/src/components/app.js文件



三列改为双列

docbox默认情况下是显示三列布局,但我们可以在app.js下进行修改使之默认为双列布局。将下图的1改为2即可切换双列模式







其他定制UI

像下图一样,我们可以修改并填写代码得到自己想要的页面样式,比如说我在最上方加了一个固定位置的区域,然后可以在这个区域添加相应的超链接等。







app.js里可以找到图中对应的标签和js代码,docbox支持多种语言切换,我们在需要的地方加入我们想要加入的标签,并在/css文件夹中对相应的css文件添加样式就可以定制我们想要的UI啦!!!



下面给大家列出一些用docbox定制API文档的网站



Mapbox API文档

Mapillary的API文档和Tiles文档

HYCON 8th

Wall

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

一篇解决 thymeleaf 下拉选的选中问题

seo达人

说明:本文基于thymeleaf3.x



在做后台系统时多多少少都会遇到下拉选回显的问题,本次就总结一下如何利用thymeleaf简单快速的进行下拉选的回显。



两种情况:

1、下拉选的数据固定死了的情况下?

利用 th:field="${要选中的option的value值}" 属性,如下

<select id="bookKind" name="bookKind" th:field="${book.bookKind}" class="form-control">

        <option value="">请选择书的种类</option>

        <option value="1">编程语言</option>

        <option value="2">数据库</option>

        <option value="3">操作系统</option>

        <option value="4">办公软件</option>

        <option value="5">图形处理与多媒体</option>

</select>

         book是请求域中的实体类,当${book.bookKind}的值和 option 的 value值匹配上后,该option就会被选中。



        怎么样是不是很简单?如果是用ajax的话,还要先获取所有的option,循环遍历,判断value值是否相等,设置selected属性值为true,跳出循环,这一系列操作,thymeleaf一个属性值就搞定,所以孰轻孰重您就看着来吧!哈哈!



2、下拉选的数据没固定死时?

两个属性  th:each="bookKind : ${bookKinds}" th:selected="{bookKind} == ${book.bookKind}" 搞定,如下所示



<select id="bookKind" name="bookKind" class="form-control">

    <option th:each="bookKind : ${bookKinds}" th:selected="
{bookKind} == ${book.bookKind}" 

            th:value="${bookKind}" th:text="${bookKind}"></option>

</select>

        解释一下,先th:each遍历,*{bookKind}代表遍历出来的元素,判断与点击的者一栏的bookKind值是否一样,如果一样th:selected的值就为true,然后th:value 设置option的value 值,th:text 设置option的文本值。



试想一下,如果是用ajax会怎么样?1、先后台获取数据后,循环append(html标签) 2、再获取到当前记录的这列属性值,再获取到 1 中循环设置的option,在比对value值,设置选中,break等。而且第一个ajax还要整成同步的,不然 2 中可能获取不到 1 中的option元素。



 



最后说明:如果恰巧能解决你的问题,那就动一动您的小手,点个赞或者评论一下,让我看到你们,您的点赞或评论将会持续带给我不懈的动力!!!come on baby!Let's go!

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

vue-router编程式的导航

seo达人

什么是编程式的导航

除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。



router.push(location, onComplete?, onAbort?)

注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。



想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。



HTML代码



<p @click="$router.push('/test/emitView')">跳转1</p>

<p @click="$router.push({path: '/test/propsView'})">path: '/test/propsView'</p>

<p @click="test">带参数的跳转</p>

<p @click="test1">提供了path,params会被忽略</p>

<p @click="$router.push({path: /test/propsView/${userId}})">

    url变为/test/propsView/123

</p>

<p @click="$router.push({path: '/test/propsView', query: {plan: 'private'}})">

    带参数的url变为/test/propsView?plan=private

</p>

Script中代码



test () {

    this.$router.push({

        name: 'routerView',

        params: {userId: this.userId, test: 333},

    })

    console.log(this.$route)

    console.log(this.$route.params)

},

test1 () {

    this.$router.push({ // 如果提供了 path,params 会被忽略

        path: 'routerView',

        params: {userId: this.userId, test: 333},

    })

    console.log(this.$route)

    console.log(this.$route.params)

},

router.replace(location, onComplete?, onAbort?)

跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。



router.go(n)

// 在浏览器记录中前进一步,等同于 history.forward()

router.go(1)

 

// 后退一步记录,等同于 history.back()

router.go(-1)

 

// 如果 history 记录不够用,则无反应

router.go(-100)

router.go(100)

router.back()

在浏览器记录中后退一步



router.forward()

在浏览器记录中前进一步


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

H5之外部浏览器唤起微信分享

seo达人

最近在做一个手机站,要求点击分享可以直接打开微信分享出去。而不是jiathis,share分享这种的点击出来二维码。在网上看了很多,都说APP能唤起微信,手机网页实现不了。也找了很多都不能直接唤起微信。

总结出来一个可以直接唤起微信的。适应手机qq浏览器和uc浏览器。

下面上代码,把这些直接放到要转发的页面里就可以了:

html部分:


        
  1. <script src="mshare.js"></script>//引进mshare.js
  2. <button data-mshare="0">点击弹出原生分享面板</button>
  3. <button data-mshare="1">点击触发朋友圈分享</button>
  4. <button data-mshare="2">点击触发发送给微信朋友</button>

js部分:


        
  1. <script>
  2. var mshare = new mShare({
  3. title: 'Lorem ipsum dolor sit.',
  4. url: 'http://m.ly.com',
  5. desc: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat inventore minima voluptates.',
  6. img: 'http://placehold.it/150x150'
  7. });
  8. $('button').click(function () {
  9. // 1 ==> 朋友圈 2 ==> 朋友 0 ==> 直接弹出原生
  10. mshare.init(+$(this).data('mshare'));
  11. });
  12. </script>

下面是mshare.js的代码分享,把这些代码新建一个js文件放进去,然后在页面中引进就ok了。


        
  1. /**
  2. * 此插件主要作用是在UC和QQ两个主流浏览器
  3. * 上面触发微信分享到朋友圈或发送给朋友的功能
  4. */
  5. 'use strict';
  6. var UA = navigator.appVersion;
  7. /**
  8. * 是否是 UC 浏览器
  9. */
  10. var uc = UA.split('UCBrowser/').length > 1 ? 1 : 0;
  11. /**
  12. * 判断 qq 浏览器
  13. * 然而qq浏览器分高低版本
  14. * 2 代表高版本
  15. * 1 代表低版本
  16. */
  17. var qq = UA.split('MQQBrowser/').length > 1 ? 2 : 0;
  18. /**
  19. * 是否是微信
  20. */
  21. var wx = /micromessenger/i.test(UA);
  22. /**
  23. * 浏览器版本
  24. */
  25. var qqVs = qq ? parseFloat(UA.split('MQQBrowser/')[1]) : 0;
  26. var ucVs = uc ? parseFloat(UA.split('UCBrowser/')[1]) : 0;
  27. /**
  28. * 获取操作系统信息 iPhone(1) Android(2)
  29. */
  30. var os = (function () {
  31. var ua = navigator.userAgent;
  32. if (/iphone|ipod/i.test(ua)) {
  33. return 1;
  34. } else if (/android/i.test(ua)) {
  35. return 2;
  36. } else {
  37. return 0;
  38. }
  39. }());
  40. /**
  41. * qq浏览器下面 是否加载好了相应的api文件
  42. */
  43. var qqBridgeLoaded = false;
  44. // 进一步细化版本和平台判断
  45. if ((qq && qqVs < 5.4 && os == 1) || (qq && qqVs < 5.3 && os == 1)) {
  46. qq = 0;
  47. } else {
  48. if (qq && qqVs < 5.4 && os == 2) {
  49. qq = 1;
  50. } else {
  51. if (uc && ((ucVs < 10.2 && os == 1) || (ucVs < 9.7 && os == 2))) {
  52. uc = 0;
  53. }
  54. }
  55. }
  56. /**
  57. * qq浏览器下面 根据不同版本 加载对应的bridge
  58. * @method loadqqApi
  59. * @param {Function} cb 回调函数
  60. */
  61. function loadqqApi(cb) {
  62. // qq == 0
  63. if (!qq) {
  64. return cb && cb();
  65. }
  66. var script = document.createElement('script');
  67. script.src = (+qq === 1) ? '//3gimg.qq.com/html5/js/qb.js' : '//jsapi.qq.com/get?api=app.share';
  68. /**
  69. * 需要等加载过 qq 的 bridge 脚本之后
  70. * 再去初始化分享组件
  71. */
  72. script.onload = function () {
  73. cb && cb();
  74. };
  75. document.body.appendChild(script);
  76. }
  77. /**
  78. * UC浏览器分享
  79. * @method ucShare
  80. */
  81. function ucShare(config) {
  82. // ['title', 'content', 'url', 'platform', 'disablePlatform', 'source', 'htmlID']
  83. // 关于platform
  84. // ios: kWeixin || kWeixinFriend;
  85. // android: WechatFriends || WechatTimeline
  86. // uc 分享会直接使用截图
  87. var platform = '';
  88. var shareInfo = null;
  89. // 指定了分享类型
  90. if (config.type) {
  91. if (os == 2) {
  92. platform = config.type == 1 ? 'WechatTimeline' : 'WechatFriends';
  93. } else if (os == 1) {
  94. platform = config.type == 1 ? 'kWeixinFriend' : 'kWeixin';
  95. }
  96. }
  97. shareInfo = [config.title, config.desc, config.url, platform, '', '', ''];
  98. // android
  99. if (window.ucweb) {
  100. ucweb.startRequest && ucweb.startRequest('shell.page_share', shareInfo);
  101. return;
  102. }
  103. if (window.ucbrowser) {
  104. ucbrowser.web_share && ucbrowser.web_share.apply(null, shareInfo);
  105. return;
  106. }
  107. }
  108. /**
  109. * qq 浏览器分享函数
  110. * @method qqShare
  111. */
  112. function qqShare(config) {
  113. var type = config.type;
  114. //微信好友 1, 微信朋友圈 8
  115. type = type ? ((type == 1) ? 8 : 1) : '';
  116. var share = function () {
  117. var shareInfo = {
  118. 'url': config.url,
  119. 'title': config.title,
  120. 'description': config.desc,
  121. 'img_url': config.img,
  122. 'img_title': config.title,
  123. 'to_app': type,
  124. 'cus_txt': ''
  125. };
  126. if (window.browser) {
  127. browser.app && browser.app.share(shareInfo);
  128. } else if (window.qb) {
  129. qb.share && qb.share(shareInfo);
  130. }
  131. };
  132. if (qqBridgeLoaded) {
  133. share();
  134. } else {
  135. loadqqApi(share);
  136. }
  137. }
  138. /**
  139. * 对外暴露的接口函数
  140. * @method mShare
  141. * @param {Object} config 配置对象
  142. */
  143. function mShare(config) {
  144. this.config = config;
  145. this.init = function (type) {
  146. if (typeof type != 'undefined') this.config.type = type;
  147. try {
  148. if (uc) {
  149. ucShare(this.config);
  150. } else if (qq && !wx) {
  151. qqShare(this.config);
  152. }
  153. } catch (e) {}
  154. }
  155. }
  156. // 预加载 qq bridge
  157. loadqqApi(function () {
  158. qqBridgeLoaded = true;
  159. });
  160. if (typeof module === 'object' && module.exports) {
  161. module.exports = mShare;
  162. } else {
  163. window.mShare = mShare;
  164. }

好了,这样就可以直接唤起微信进行分享啦

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

calc的使用

seo达人

       有张页面是要求要一屏展示,我想到了媒体查询,也想到了vw和vh。我先用vw和vh来布局,分为上,中,下三部分。每块计算宽高,vw和vh可以实现响应式布局,所以就用上了。但媒体查询用上了却发现在这边不好用,这时使用上了calc()属性。因为上一个人引入了video.js并加上id:#myVideo ,这边也做相应的计算处理。



注意:要有空格



calc()能计算的计算表达式里,在加号(“+”)和减号(“-”)两边要留空格,而乘号(“”)和除号(“”)没有这个要求。 



.video_rel {

        height: calc(100% - 66px);

        width: calc(51.3% - 60px);

 

        #myVideo {

            width: 100%;

            height: 100%;

        }

    }

CSS3引入了一个有用的功能,就是calc()函数。在指定元素高度或宽度时,你可以基于计算设定,而不是简单的使用固定数值。这种功能在自适应网页布局设计中格外有用——针对不同尺寸的设备,你需要动态的调整元素的大小,产生适合屏幕大小的不同布局。

 

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

六、HTTP协议中的缓存

seo达人

一、缓存简介

缓存无处不在,浏览器端的缓存、服务器端的缓存、代理服务器的缓存、对象缓存、数据库也有缓存……HTTP中具有缓存功能的是浏览器缓存和代理服务器缓存。下面说一下缓存的优点:



1.减少冗余的数据传输,节省了传输时间



2.减少服务器的负担,大大提高了网站的性能



3.加快了客户端加载网页的速度



二、使用Fiddler如何查看缓存的Header

与缓存相关的内容放在Header中的Cache项里;Requests和Responses均是这样。如图:







三、缓存的新鲜度(通过什么方式判断其是否,如何刷新缓存)

Web服务器通过两种方式判断浏览器缓存是否:



(1)浏览器把缓存文件的最后修改时间通过Header“If-Modified-Since”项传递给Web服务器。



(2)浏览器把缓存文件的ETag通过Header“If-None-Match”项传递给Web服务器。



简单描述一下,浏览器端想请求一个文档,它首先检查本地缓存,发现存在这个文档的缓存,获取缓存文档的最后修改时间,发送请求,将值放在Header中的“If-Modified-Since”项传递给Web服务器。Web服务器接收到请求后,将服务器的文档修改时间(Last-Modified)与HTTP请求中的header中的“If-Modified-Since”值相比较,有两种情况,如下面图示:



1.缓存有效:







2.缓存无效:







截图举例:







上面说的是If-Modified-Since值对比的方式;下面说一下ETa'g;



四、ETag

ETag(Entity Tag):实体标签;是根据实体内容生成的一段hash字符串(类似MD5之后的结果),可以用来标识资源的状态(当资源发送变化时,ETag也会跟着改变);ETag是Web服务端产生的,然后通过response响应给浏览器。使用ETag,主要解决Last-Modified无法解决的情况:



(1.某些服务器不能得到文件的If-Modified-Since来判断文件是否更新;



(2.某些文件修改非常频繁,以小于秒的单元进行修改,而Last-Modified最单元为秒;



(3.有些文件最后修改时间变化了,但是内容并没有变化,所以我们不希望浏览器以为文件已变化了;







五、与缓存相关的header

字段名称 释义

Cache-Control:max-age=0 以秒为单位

If-Modified-Since:Fri, 11 Jan 2019 01:55:04 GMT 缓存文件的最后修改时间

If-None-Match:W/"5c37f778-732" 缓存文件的Etag的值

Cache-Control:no-cache 不使用缓存

Pragma:no-cache 不使用缓存

Cache-Control:public 响应被缓存,可以共享与多用户

Cache-Control:private 响应只能私有缓存,不可共享

Cache-Control:no-store 绝对禁止缓存(机密、敏感文件)

Cache-Control:max-age=60 60秒后缓存过期(相对时间)

Date:Fri, 11 Jan 2019 01:55:04 GMT 当前发送时间

Expires:Fri, 11 Jan 2019 01:55:04 GMT 缓存过期时间设置(绝对时间)

Last-Modified:Fri, 11 Jan 2019 01:55:04 GMT 服务器端文件的最后修改时间

Etag:W/"5c37f778-732" 服务器端文件的Etag值

六、关于缓存的常识

1.如何让浏览器不使用缓存?



答:【Ctrl+F5】快捷键强制刷新浏览器,让浏览器不使用缓存;此时Fiddler抓包所看到的请求Header中都会带有Cache-Control:no-cache;







2.如何让浏览器直接使用缓存,不请求服务器进行缓存验证?



答:第一次访问与第二次访问同一个网页;(注意:第二次访问时,输入网址,直接回车)浏览器会直接使用有效的缓存,而不会发生HTTP请求去服务器验证缓存,这种情况称之为缓存命中;



使用Fiddler抓包,现象:第一次访问,有70多个Session;第二次访问,仅40多个请求;



3.浏览器均可在设置中设置不使用缓存;



4.公有缓存、私有缓存的区别:一个可以多个不同的客户端使用,一个只可唯一的客户端使用;


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

JS中钩子函数与回调函数的区别

seo达人

测试代码

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <title>Title</title>

</head>

<body>

    <button id="btn">按钮</button>

    <script>

        let btn = document.getElementById("btn");

        btn.onclick = () => { // 钩子函数

            console.log('我是钩子函数');

        }

 

        btn.addEventListener("click",() =>{ // 回调函数

            console.log('我是回调函数');

        });

        // 这是给btn绑定了一个监听器,后面那个函数是它的回调函数,

        // 因为消息捕获的过程我们并不能参与,而在捕获执行完毕的时候,

        // 回调函数才会执行,我们可以把对消息的处理写在回调函数里。

    </script>

</body>

</html>

点击按钮后代码输出如下:







回调函数和钩子函数的区别根本上是

钩子函数在捕获消息的第一时间就执行,而回调函数是捕获结束时,最后一个被执行的。



什么是钩子函数

一般认为,钩子函数就是回调函数的一种,其实还是有差异的,差异地方就是:触发的时机不同。

钩子(Hook)概念源于Windows的消息处理机制,通过设置钩子,应用程序对所有消息事件进行拦截,然后执行钩子函数。 



什么是回调函数

回调函数其实是调用者将回调函数的指针传递给了调用函数,当调用函数执行完毕后,通过函数指针来调用回调函数。



钩子函数和回调函数都是事件处理函数


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

数组常用的方法

seo达人

数组常见方法

数组的方法

一、join() 方法 ----->不会改变原数组

二、concat() 方法 ----->不会改变原数组

三、splice(index, num, item) ----->会改变原数组

  1. splice(index, num) 删除功能
  2. splice(index, 0, ...item)
  3. splice(index, num, item)
  4. splice(index)

    四、slice() -----> 不会改变原数组

    五、push() 和 pop() ----->会改变原数组

    六、shift() 和 unshift() -----> 会改变原数组

    七、sort() -----> 会改变原数组

    八、reverse() ----->会改变原数组

    九、indexOf() 和 lastIndexOf()

    十、includes()

    十一、forEach()

    十二、map() -----> 不会改变原数组

    十三、filter() -----> 不会改变原数组

    十四、every()

    十五、some()

    十六、reduce() 和 reduceRight()

    十七、Array.from() 将类数组转化为数组

    十八、Array.of() 方法用于将一组值转化为数组

    十九、数组实例的 find() 和 findIndex()

    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    数组的方法

    一、join() 方法 ----->不会改变原数组

    该方法可以将数组里面的元素,通过指定的分隔符以字符串的形式连接起来

    返回值:返回新的字符串



    // join() 将数组转化为字符串

    let arr = [1, 2, 3, 4, 5]

    let str1 = arr.join('|')

    console.log(arr) // [1, 2, 3, 4, 5]

    console.log(str1) // 1|2|3|4|5

    // 当传空字符串时

    let str2 = arr.join('') // 12345

    // 当不传时

    let str3 = arr.join() // 1,2,3,4,5

    1

    2

    3

    4

    5

    6

    7

    8

    9

    二、concat() 方法 ----->不会改变原数组

    该方法可以把两个数组里的元素拼接成一个新的数组

    返回值:返回拼接后的新数组



    let arr1 = [0, 1, 2]

    let arr2 = [2, 3, 4]

    let arr = arr1.concat(arr2)

    // 传入二维数组

    let arrCopy = arr1.concat([12, [17, 26]])

    console.log(arrCopy) // [0, 1, 2, 12, [17, 26]]

    console.log(arr) // [0, 1, 2, 2, 3, 4]

    console.log(arr1) // [0, 1, 2]

    console.log(arr2) // [2, 3, 4]



    // ES6 扩展运算符

    let a = [1, 2]

    let b = [2, 3]

    let ab = [...a, ...b] // [1, 2, 2, 3]

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    三、splice(index, num, item) ----->会改变原数组

    index 参数:必传,整数,规定添加或者删除的位置,使用负数时,从数组尾部规定位置

    num 参数:必传,要删除的数量,如果为 0,则不删除项目

    item 参数:可选参数,可以是多个,想数组添加的新项目

    splice 具有删除,插入,替换的功能


  5. splice(index, num) 删除功能

    index 参数:开始位置的索引



    num 参数:要删除元素的个数



    返回值:返回的是包含被删除元素的数组对象



    // 删除功能

    let array = [1, 2, 3, 4, 5]

    let newArr = array.splice(2, 2)

    console.log(newArr) // [1, 2, 5]

    console.log(array) // [3, 4]



    1

    2

    3

    4

    5

    6
  6. splice(index, 0, …item)

    index 参数:插入元素的索引值

    0 参数:不删除

    // 插入功能

    let arr = ['a', 'b', 'c', 'd', 'e']

    let newArr = arr.splice(1, 0, ['插入', 1217])

    console.log(newArr) // []

    console.log(arr) // ['a', ['插入', 1217], 'b', 'c', 'd', 'e']



    1

    2

    3

    4

    5

    6
  7. splice(index, num, item)

    index 参数:开始的索引位置

    num 参数:删除的项个数

    item 参数:替换项

    返回值:返回包含被删除的元素的数组对象

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(2, 2, '替换', '1226')

    console.log(newArr) // [3, 4]

    console.log(arr) // [1, 2, '替换', '1226', 5]



    1

    2

    3

    4

    5
  8. splice(index)

    当只传一个值时,表示从传入的 index 索引值开始截取到最后

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(3)

    console.log(newArr) // [4, 5]

    console.log(arr) // [1, 2, 3]

    1

    2

    3

    4

    四、slice() -----> 不会改变原数组

    返回从原数组中指定开始下标到结束下标之间的项组成的新数组

    slice() 方法可以接受一或两个参数,即要返回项的起始位置和结束位置

    array.slice(2) 若只设置一个参数,起始位置为2(包含下标2)开始到数组最后

    array.slice(2, 5) 若设置两个参数,起始下标为2(包含下标2)到结束下标5(不包含下标5)的数组

    当 slice() 参数中有负数时,将负数加上数组的长度值来替换该位置的数

    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

    let copyArr1 = arr.slice(2) // [3, 4, 5, 6, 7, 8, 9]

    let copyArr2 = arr.slice(2, 5) // [3, 4, 5] 

    let copyArr3 = arr.slice(-2) // [8, 9]

    let copyArr4 = arr.slice(2, -2) // [3, 4, 5, 6, 7]

    let copyArr5 = arr.slice(-2, -5) // []

    let copyArr6 = arr.slice(-5, -2) // [5, 6, 7]

    console.log(arr) // [1, 2, 3, 4, 5, 6, 7, 8, 9]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    五、push() 和 pop() ----->会改变原数组

    push() 可以接受任意数量的参数,将其逐个添加到数组的末尾,并返回修改后数组的长度(改变了原数组)

    pop() 删掉数组末尾最后一项,改变了数组的 length 值,并返回删除的项

    let arr = [1, 2, 3, 4, 5]

    let count = arr.push(0, 1217)

    console.log(count) // 7

    console.loh(arr) // [1, 2, 3, 4, 5, 0, 1217]



    let item = arr.pop()

    console.log(item) // 1217

    console.log(arr) // [1, 2, 3, 4, 5, 0]

    1

    2

    3

    4

    5

    6

    7

    8

    六、shift() 和 unshift() -----> 会改变原数组

    shift() 删除原数组的第一项,并返回删除元素的值,如果数组为空折返回 undefined

    unshift() 将参数添加到原数组的开头,并返回数组的长度

    let arr = [1, 2, 3, 4, 5]

    let item = arr.shift()

    console.log(item) // 1

    console.log(arr) // [2, 3, 4, 5]



    let count = arr.unshift(0, 'Jack')

    console.log(count) // 6

    console.log(arr) // [0, 'Jack', 2, 3, 4, 5]

    1

    2

    3

    4

    5

    6

    7

    8

    七、sort() -----> 会改变原数组

    在排序时,sort() 方法会调用每个数组项的 toString() 转型方法,然后比较得到的字符串,已确定如何排序,其本质是比较字符串的 ASCII 编码

    即使数组中的每一项都是数值,sort() 方法比较的也是字符串,因此会出现以下情况:

    let arr1 = ['a', 'd', 'e', 'b', 'c']

    console.log(arr1.sort()) // ['a', 'b', 'c', 'd', 'e']



    let arr2 = [12, 26, 3, 99, 52]

    console.log(arr2.sort()) // [12, 26, 3, 52, 99]



    1

    2

    3

    4

    5

    6

    解决办法



    let arr3 = [12, 26, 3, 99, 52]

    arr3.sort((a, b) => {

    return a -b

    })

    console.log(arr3) // [3, 12, 26, 52, 99]

    1

    2

    3

    4

    5

    冒泡排序(优化版)



    function mySort (arr) {

    let count = 0 // 记录循环次数

    // 外层循环  控制循环的次数,每次找到最大值

    for (let i = 0; i < arr.length - 1; i++) {

    count++

    // 判断是否排序好了

    let isSort = true // 初始值默认已经排序好了

    for (let j = 0; j < arr.length - 1 - i; j++) {

    count++

    if (arr[j] > arr[j + 1]) {

    isSort = false

    // 交换位置

    let tmp = arr[j]

    arr[j] = arr[j + 1]

    arr[j + 1] = tmp

    }

    }

    // 某一趟结束,判断一下是否结束

    // 如何判断是否排序好,根据是否发生了位置交换,如果发生了位置交换就说明没有排序好

    if (isSort) {

    break

    }

    }

    console.log(count)

    return arr

    }

    mySort([12, 26, 17, 520, 99])



    // 打印结果:count 9

    // arr [12, 17, 26, 99, 520]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    八、reverse() ----->会改变原数组

    反转数组项的顺序

    let arr = [1, 2, 3, 4, 5]

    arr.reverse()

    console.log(arr) // [5, 4, 3, 2, 1]



    1

    2

    3

    4

    九、indexOf() 和 lastIndexOf()

    indexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中从数组的开头开始向后查找

    lastIndexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中是从数组的末尾开始向前查找

    返回值:当存在时,返回要查找的项在数组中首次出现的索引值;当不存在时,返回 -1

    可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 5, 7, 7, 8, 5, 12, 17]

    console.log(arr.indexOf(5)) // 3

    console.log(arr.lastIndexOf(5)) // 7



    console.log(arr.indexOf(5, 2)) // 3

    console.log(arr.lastIndexOf(5, 4)) // 3



    console.log(arr.indexOf('5')) // -1

    1

    2

    3

    4

    5

    6

    7

    8

    十、includes()

    Array.prototype.includes() 数组实例的方法

    返回一个布尔值,表示某个数组是否包含给定的值

    推荐使用:可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 4, 5]

    console.log(arr.includes(3)) // true

    console.log(arr.includes(0)) // false

    1

    2

    3

    十一、forEach()

    对数组进行遍历,对数组中的每一项运行给定函数,没有返回值



    forEarch(function (item, index, array) {})



    参数 item:表示数组中的每一项

    参数 index:表示数组中每一项对应的索引值

    参数 array:表示数组本身

    let arr = [1, 2, 3, 4, 5]

    arr.forEach((item, index, array) => {

    console.log(item + '---' + index + '---' + (arr === array))

    })

    1

    2

    3

    4

    十二、map() -----> 不会改变原数组

    map() 方法是将数组中的每一项调用提供的函数,结果返回一个新数组,并没有改变原来的数组

    映射



    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.map(item => item * item)



    console.log(newArr) // [1, 4, 9, 16, 25]

    console.log(arr) // [1, 2, 3, 4, 5]

    1

    2

    3

    4

    5

    十三、filter() -----> 不会改变原数组

    filter() 方法是将数组中所有的元素进行判断,将满足条件的元素作为一个新数组返回

    过滤



    let arr = [12, 17, 26, 520, 1314]

    let newArr = arr.filter((item, index) => {

    return item > 20

    })

    console.log(newArr) // [26, 520, 1314]

    1

    2

    3

    4

    5

    十四、every()

    every() 判断数组中每一项都是否满足条件,只有所有项都满足条件才返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean1 = arr.every(item => item > 0)

    let boolean2 = arr.every(item => item > 3)



    console.log(boolean1) // true

    console.log(boolean2) // false

    1

    2

    3

    4

    5

    6

    十五、some()

    some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean3 = arr.some(item => item > 3)

    let boolean4 = arr.some(item => item < 0)



    console.log(boolean3) // true

    console.log(boolean4) // false

    1

    2

    3

    4

    5

    6

    十六、reduce() 和 reduceRight()

    reduce() 方法是所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型

    接受两个参数:每一项调用的函数和作为归并基础的初始值(可选项)

    这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。



    // 利用 reduce() 方法实现数组求和,给数组一开始家里一个初始值 3

    let arr = [1, 2, 3, 4, 5]

    let sum = arr.reduce((prev, cur, index, array) => {

    // 函数接受 4 个参数:

    // 前一个值、当前值、项的索引值、原数组对象

    console.log(prev, '---', cur, '---', index, '---', array)

    return prev + cur

    }, 3)

    console.log(sum) // 18 = 15 + 3

    1

    2

    3

    4

    5

    6

    7

    8

    9

    与之相对应的还有一个 Array.reduceRight() 方法,区别是这个是从右向左操作的



    十七、Array.from() 将类数组转化为数组

    let arrayLike = {

    '0': 'a',

    '1': 'b',

    '2': 'c',

    '3': 'd',

    length: 4

    }

    // ES5 写法

    let arr1 = [].slice.call(arrayLike) // ['a', 'b', 'c', 'd']



    // ES6

    let arr2 = Array.from(arrayLike) // ['a', 'b', 'c', 'd']

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    十八、Array.of() 方法用于将一组值转化为数组

    Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。



    Array.of(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]

    Array.of('abcd') // ['abcd']

    Array.of('abcd').length // 1

    Array.of() // []



    // Array.of 方法的实现

    function ArrayOf () {

    return [].slice.call(arguments)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    十九、数组实例的 find() 和 findIndex()

    数组实例的 find() 方法,用于找出第一个符合条件的数组成员

    它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后就返回该成员,如果没有符合条件的成员,则返回 undefined

    let arr = [1, 2, 3, 4, 5]

    let value= arr.find((item, index, array) => {

    // item 表示循环遍历数组的每一项

    // index 每一项对应的索引值

    // array 原数组对象

    return item > 3

    })

    console.log(value) // 4

    console.log(arr) // [1, 2, 3, 4, 5]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    数组实例的 findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回 -1

    let arr = [1, 2, 3, 4, 5]

    let index = arr.findIndex((item, index, array) => {

    return item > 3

    })



    console.log(index) // 3



    [NaN].indexOf(NaN) // -1

    [NaN].findIndex(value => Object.is(NaN, value)) // 0

    [NaN].includes(NaN) // true

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    由此可见:一般用来判断数组中是否存在某个值,推荐使用 includes



    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    let arr = [1, [2, 3, [4, 5, [6]]]]

    let arrFlat = arr.flat(Infinity)

    console.log(arrFlat) // [1, 2, 3, 4, 5, 6]

    console.log(arr) // [1, [2, 3, [4, 5, [6]]]]

    1

    2

    3

    4

    利用递归实现数组扁平化



    let arrayFlat = []

    let myFlat = (arr) => {

    for (let i = 0; i < arr.length; i++) {

    let item= arr[i]

    // 判断 arr[i] 是否是数组

    if (Array.isArray(item)) {

    // 如果是数组,继续调用函数 myFlat

    myFlat(item)

    } else {

    arrayFlat.push(item)

    }

    }

    return arrayFlat

    }



    蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

彻底解决小程序无法触发SESSION问题

seo达人

一、首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来

wx.request({
  ......
  success: function(res) {
    console.log(res.header);
    //set-cookie:PHPSESSID=ic4vj84aaavqgb800k82etisu0; path=/; domain=.fengkui.net

    // 登录成功,获取第一次的sessionid,存储起来
    // 注意:Set-Cookie(开发者工具中调试全部小写)(远程调试和线上首字母大写)
    wx.setStorageSync("sessionid", res.header["Set-Cookie"]);
  }
}) 

二、请求时带上将sessionid放入request的header头中传到服务器,服务器端可直接在cookie中获取

wx.request({
  ......
  header: {
    'content-type': 'application/json', // 默认值
    'cookie': wx.getStorageSync("sessionid")
    //读取sessionid,当作cookie传入后台将PHPSESSID做session_id使用
  },
  success: function(res) {
    console.log(res)
  }
}) 

三、后台获取cookie中的PHPSESSID,将PHPSESSID当作session_id使用

<?php
// 判断$_COOKIE['PHPSESSID']是否存在,存在则作session_id使用
if ($_COOKIE['PHPSESSID']) {
    session_id($_COOKIE['PHPSESSID']);
}

session_start();
echo session_id(); 

jqGrid 表格底部汇总、合计行footerrow处理

seo达人

jqGrid提供了表格底部汇总、合计行功能,我们先看下user-guide关于jqGrid合计行都有哪些说明?然后再看个DEMO,看看jqGrid表格底部汇总、合计行到底如何实现。



1、user-guide关于jqGrid合计行的说明

1)表格配置:footerrow, boolean, 默认false

If set to true this will place a footer table with one row below the gird records and above the pager. The number of columns equal those specified in colModel

表格是否显示底部合计行。



2)表格配置:userDataOnFooter,boolean,默认false

When set to true we directly place the user data array userData in the footer if the footerrow parameter is set to true. The rules are as follows: If the userData array contains a name which matches any name defined in colModel, then the value is placed in that column. If there are no such values nothing is placed. Note that if this option is used we use the current formatter options (if available) for that column. See footerData method.

如果设为true,则userData可以用来填充汇总行。



3)汇总行赋值:footerData([string action], [object data], [boolean format])

This method gets or sets data on the grid footer row. When set data in the footer row, the data is formatted according to the formatter (if defined) in coModel. The method can be used if footerrow option is set to true.

parameters

string action - can be ‘get’ or ‘set’. The default is get. ‘get’ returns an object of type name:value, where the name is a name from colModel. This will return data from the footer. The other two options have no effect in this case. ‘set’ takes a data object and places the values in the footer The value is formatted according to the definition of the formatter in colModel - see next parameter. The object should be in name:value pair, where the name is the name from colModel

object data - data to be set in the footer in name:value pair, where the name should correspond to the name of colModel in order to be set in the appropriate cell.

boolean format - default is true. This instruct the method to use the formatter (if set in colModel) when new values are set. A value of false will disable the using of formatter



2、一个DEMO,如何利用gridComplete事件进行表格数据汇总并赋值给合计行

1)案例截图



2)html代码



<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>jggrid底部汇总行</title>



<link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/jqueryui/1.11.0/jquery-ui.min.css" />

<link rel="stylesheet" href="https://js.cybozu.cn/jqgrid/v5.3.1/css/ui.jqgrid.css" />

<script src="https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/jquery.jqGrid.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/i18n/grid.locale-en.js"&gt;&lt;/script&gt;

</head>

<body>

<div class="page-content container">

<div class="page-body"> <!-- page-body -->

<div class="panel panel-default" id="panel-orders">

<table id="orders"></table>

</div>

</div>

</div>

<script type="text/javascript">

var data = [];

function getBills() {

var rowCount = 10;

for (var i = 0; i < rowCount; i ++) {

data.push({

sid: i,

goods_no: i + 1,

goods_name: '零件名称' + rowCount + i,

car_type_name: '车型' + rowCount + i,

package_name: '包装器具' + rowCount + i,

unit_name: '件',

snp: 0.89,

bill_amount: rowCount + i,

goods_count: rowCount + i,

bill_no: 'BN0000000' + i,

qrcode: '1000000000' + i,

barcode: '1000000000' + i,

})

}

$("#orders").jqGrid("clearGridData").jqGrid('setGridParam',{data: data || []}).trigger('reloadGrid');

}

$(function() {

$("#orders").jqGrid({

colModel: [

{label: "零件号", name: "goods_no", width: 60},

{label: "零件名称", name: "goods_name", search:false, width: 180},

{label: "车型", name: "car_type_name", width: 70},

{label: "包装器具", name: "package_name", width: 70},

{label: "单位", name: "unit_name", width: 40},

{label: "订单号", name: "bill_no", width: 120},

{label: "订单数量", name: "goods_count", width: 80},

],

datatype: 'local',

rownumbers: true,

height: 300,

rowNum: 1000,

footerrow: true,

gridComplete: function() {

var rows = $("#orders").jqGrid("getRowData"), total_count = 0;

        for(var i = 0, l = rows.length; i<l; i++) {

        total_count += (rows[i].goods_count - 0);

        }

        $("#orders").jqGrid("footerData", "set", {goods_name:"--合计--",goods_count:total_count});

        }

});

getBills();

});

</script>

</body>

</html>



3)代码说明:



表格构建时,设置:footerrow: true

gridComplete(jqGridGridComplete)事件处理,进行数据汇总并赋值给合计行

gridComplete fires after all the data is loaded into the grid and all other processes are complete. Also the event fires independent from the datatype parameter and after sorting paging and etc. Does not fire if datatype is a defined as function.



4)获取汇总行数据

var row = $("#orders").jqGrid(“footerData”, “get”);

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档