<address id="ttjl9"></address>

      <noframes id="ttjl9"><address id="ttjl9"><nobr id="ttjl9"></nobr></address>
      <form id="ttjl9"></form>
        <em id="ttjl9"><span id="ttjl9"></span></em>
        <address id="ttjl9"></address>

          <noframes id="ttjl9"><form id="ttjl9"></form>

          首頁

          微信小程序之卡片層疊滑動效果

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          微信小程序之卡片層疊滑動效果

          代碼:
          js:

          // index/gun/jsSwiper2/jsSwiper2.js
          Page({

            /**
             * 頁面的初始數據
             */
            data: {
              startX: 0,
              endX: 0,
              iCenter: 3,
              datas: [{
                id: 1,
                zIndex: 2,
                opacity: 0.2,
                left: 40,
                iamge: "../../images/1.jpg",
                animation: null
              },
              {
                id: 2,
                zIndex: 4,
                opacity: 0.4,
                left: 80,
                iamge: "../../images/2.jpg",
                animation: null
              },
              {
                id: 3,
                zIndex: 6,
                opacity: 0.6,
                left: 120,
                iamge: "../../images/3.jpg",
                animation: null
              },
              {
                id: 4,
                zIndex: 8,
                opacity: 1,
                left: 160,
                iamge: "../../images/4.jpg",
                animation: null
              },
              {
                id: 5,
                zIndex: 6,
                opacity: 0.6,
                left: 200,
                iamge: "../../images/5.jpg",
                animation: null
              },
              {
                id: 6,
                zIndex: 4,
                opacity: 0.4,
                left: 240,
                iamge: "../../images/6.jpg",
                animation: null
              },
              {
                id: 7,
                zIndex: 2,
                opacity: 0.2,
                left: 280,
                iamge: "../../images/7.jpg",
                animation: null
              },
              ],
              order: []
            },

            /**
             * 生命周期函數--監聽頁面加載
             */
            onLoad: function (options) {
              this.__set__();
              this.move();
            },

            /**
             * 生命周期函數--監聽頁面初次渲染完成
             */
            onReady: function () {

            },

            /**
             * 生命周期函數--監聽頁面顯示
             */
            onShow: function () {

            },

            /**
             * 生命周期函數--監聽頁面隱藏
             */
            onHide: function () {

            },

            /**
             * 生命周期函數--監聽頁面卸載
             */
            onUnload: function () {

            },

            /**
             * 頁面相關事件處理函數--監聽用戶下拉動作
             */
            onPullDownRefresh: function () {

            },

            /**
             * 頁面上拉觸底事件的處理函數
             */
            onReachBottom: function () {

            },

            /**
             * 用戶點擊右上角分享
             */
            onShareAppMessage: function () {

            },
            move: function () {
              var datas = this.data.datas;
              /*圖片分布*/
              for (var i = 0; i < datas.length; i++) {
                var data = datas[i];
                var animation = wx.createAnimation({
                  duration: 200
                });
                animation.translateX(data.left).step();
                this.setData({
                  ["datas[" + i + "].animation"]: animation.export(),
                  ["datas[" + i + "].zIndex"]: data.zIndex,
                  ["datas[" + i + "].opacity"]: data.opacity,
                })
              }
            },
            /**左箭頭 */
            left: function () {
              //
              var last = this.data.datas.pop(); //獲取數組的最后一個
              this.data.datas.unshift(last);//放到數組的第一個
              var orderFirst = this.data.order.shift();
              this.data.order.push(orderFirst);
              this.move();
            },
            /** */
            right: function () {
              var first = this.data.datas.shift(); //獲取數組的第一個
              this.data.datas.push(first);//放到數組的最后一個位置
              var orderLast = this.data.order.pop();
              this.data.order.unshift(orderLast);
              this.move();
            },
            /**點擊某項 */
            choose: function (e) {
              var that = this;
              var id = e.currentTarget.dataset.id;
              var order = that.data.order;
              var index = 0;
              for (var i = 0; i < order.length; i++) {
                if (id == order[i]) {
                  index = i;
                  break;
                }
              }
              if (index < that.data.iCenter) {
                for (var i = 0; i < that.data.iCenter - index; i++) {
                  this.data.datas.push(this.data.datas.shift()); //獲取第一個放到最后一個
                  this.data.order.unshift(this.data.order.pop());
                  // this.right()  
                }
              } else if (index > that.data.iCenter) {
                for (var i = 0; i < index - that.data.iCenter; i++) {
                  this.data.datas.unshift(this.data.datas.pop()); //獲取最后一個放到第一個
                  this.data.order.push(this.data.order.shift());
                  // this.left();
                }
              }
              this.move();
            },
            /**新的排列復制到新的數組中 */
            __set__: function () {
              var that = this;
              var order = that.data.order;
              var datas = that.data.datas;
              for (var i = 0; i < datas.length; i++) {
                that.setData({
                  ["order[" + i + "]"]: datas[i].id
                })
              }
            },
            //手指觸發開始移動
            moveStart: function (e) {
              console.log(e);
              var startX = e.changedTouches[0].pageX;
              this.setData({
                startX: startX
              });
            },
            //手指觸摸后移動完成觸發事件
            moveItem: function (e) {
              console.log(e);
              var that = this;
              var endX = e.changedTouches[0].pageX;
              this.setData({
                endX: endX
              });
              //計算手指觸摸偏移劇距離
              var moveX = this.data.startX - this.data.endX;
              //向左移動
              if (moveX > 20) {
                this.left();
              }
              if (moveX < -20) {
                this.right();
              }
            },
          })


          wxml:

          <view class="teachers_banner">
            <view class="container clearfix teachers_b">
              <view class="slide" id="slide" bindtouchstart='moveStart' bindtouchend='moveItem'>

                <block wx:for="{{datas}}">
                  <li animation="{{item.animation}}" style="z-index: {{item.zIndex}} ;opacity:{{item.opacity}};" bindtap="choose" data-id="{{item.id}}">
                    <image src="{{item.iamge}}"></image>
                  </li>
                </block>

              </view>
            </view>
          </view>

          wxss:

          .teachers_banner {
            width: 100%;
            height: 650px;
            background-size: cover;
            position: relative;
            overflow: hidden;
          }

          .teachers_b {
            position: relative;
            margin-top: 80px;
          }

          #slide {
            margin: 0 auto;
            width: 100%;
            height: 350px;
            position: relative;
          }

          image {
            width: 400rpx;
            height: 550rpx;
          }

          #slide li {
            position: absolute;
            width: 400rpx;
            display: -webkit-box;
            display: -webkit-flex;
            display: flex;
            align-items: flex-start;
            -webkit-box-align: flex-start;
            -webkit-align-items: flex-start;
            overflow: hidden;
            box-shadow: 0 0 20px #1d374d;
          }

          #slide li img {
            width: 100%;
            height: 100%;
          }

          .slide_right {
            padding: 40px;
            -webkit-box-flex: 1;
            -webkit-flex: 1;
            flex: 1;
            min-width: 0;
          }

          .slide_right dl {
            padding-top: 10px;
          }

          .arrow .prev, .arrow .next {
            position: absolute;
            width: 50px;
            top: 38%;
            z-index: 9;
            font: 700 96px 'simsun';
            opacity: 0.3;
            color: #fff;
            cursor: pointer;
          }

          效果:
          1.左右滑動時,向相應方向移動一個卡片位置;
          2.點擊某一項時,將點擊項位置移動到中間位置;

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、網站建設 、平面設計服務



          前端 之 jQuery

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          文章目錄
          jQuery
          jQuery的安裝:
          jQuery 語法
          選擇器
          基本選擇器:
          層級選擇器
          基本篩選器
          樣式操作
          表單篩選器
          遍歷方法
          jQuery鏈式操作
          jQuery 事件
          $(document).ready()
          click()
          dblclick()
          mouseenter()
          mouseleave()
          mousedown()
          mouseup()
          hover()
          focus()
          blur()
          input()
          取消標簽默認的事件
          事件冒泡
          事件委托
          jQuery自帶的動畫效果
          jQuery
          jQuery的字面意思其實就是JavaScript和查詢(Query),即用于輔助開發JavaScript的庫。jQuery 極大地簡化了 JavaScript 編程,jQuery使用戶可以更加方便地處理HTML(標準通用標記語言下的一個應用)、events、實現動畫效果,而且方便地為網站提供AJAX交互。

          實例找到div標簽并給div標簽設置為紅色

          原生js操作
          var d1Ele = document.getElementById('d1');
          d1Ele.style.color = 'red';
          jQuery操作
          $('#d1').css('color','blue');
          1
          2
          3
          4
          5
          jQuery的安裝:
          您可以從網頁中添加 jQuery

          1、從官網http://jquery.com/download/下載 jQuery 庫

          里面分為:Production version(用于實際的網站中,已被精簡和壓縮)和Development version(用于測試和開發,未壓縮,是可讀的代碼),一般使用Production version壓縮版本的。

          2、從 CDN 中載入 jQuery, 如從 Google 或 百度 中加載 jQuery

          <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
          或者
          <script src="http://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script>
          或者
          <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.slim.js"></script>
          1
          2
          3
          4
          5
          一定要先導入后使用

          jQuery 語法
          jQuery 語法是通過選取 HTML 元素,并對選取的元素執行某些操作。

          $(selector).action()
          1
          美元符號定義 jQuery
          選擇符(selector)“查詢"和"查找” HTML 元素
          jQuery 的 action() 執行對元素的操作
          選擇器
          jQuery 選擇器可以對 HTML 元素組或單個元素進行操作。 jQuery 選擇器基于元素的 id、類、類型、屬性、屬性值等查找HTML 元素。它基于已經存在的 CSS 選擇器外,還有一些自定義的選擇器。

          基本選擇器:
          ID選擇器、類名選擇器、標簽選擇器、組合選擇器

          選擇器 實例 選取
          * $("*") 所有元素
          #id $("#d1") id=“d1” 的元素
          .class $(".name") class=“name” 的所有元素
          .class , .class $(".name,.password") class 為 “name” 或 “password” 的所有元素
          *element $(“span”) 所有 <span> 元素
          el1,el2,el3 $(“h1,div,p”) 所有 <h1>、<div> 和 <p> 元素
          提出注意點,原生DOM查找和jQuery查找出來的結果區別DOM對象與jQuery對象
          DOM對象與jQuery對象互相轉換
          $('#d1')[0]
          var d1Ele = document.getElementById('d1');
          $(d1Ele)
          1
          2
          3
          4
          層級選擇器
          選擇器 實例 選取
          parent > child $(“div > p”) <div> 元素的直接子元素的所有 <p> 元素
          parent descendant $(“div p”) <div> 元素的后代的所有 <p> 元素
          element + next $(“div + p”) 每個 <div> 元素相鄰的下一個 <p> 元素
          element ~ siblings $(“div ~ p”) <div> 元素同級的所有 <p> 元素
          基本篩選器
          選擇器 實例 選取
          :first $(“p:first”) 第一個 <p> 元素
          :last $(“p:last”) 最后一個 <p> 元素
          :even $(“tr:even”) 所有偶數 <tr> 元素
          :odd $(“tr:odd”) 所有奇數 <tr> 元素
          :gt(nu) $(“ul li:gt(3)”) 列舉 index 大于 3 的元素
          :lt(nu) $(“ul li:lt(3)”) 列舉 index 小于 3 的元素
          :eq(nu) $(“ul li:eq(3)”) 列舉 index 等于 3 的元素
          :not(selector) $(“input:not(:empty)”) 所有不為空的輸入元素
          :has(element) $(“div:has(a)”) 返回擁有一個或多個元素在其內的所有元素
          /用ul標簽舉例
          $('#ul>li:first')
          $('#u1>li:last')
          $('#ul>li:eq(3)')
          $('#ul>li:even')
          $('#ul>li:odd')
          $('#ul>li:gt(3)')
          $('#ul>li:lt(3)')
          $('#u1>li:not(.c1)')

          最后一個has的玩法需要寫個三個div:一個空div、一個兒子有a標簽、一個兒子沒有a,孫子有a標簽
          $('div:has(a)')
          輸出:
          k.fn.init(3) [div, div#d2, div#d3, prevObject: k.fn.init(1)]
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          樣式操作
          方法 描述
          addClass() 向被選元素添加一個或多個類名
          after() 在被選元素后插入內容
          append() 在被選元素的結尾插入內容
          appendTo() 在被選元素的結尾插入 HTML 元素
          attr() 設置或返回被選元素的屬性/值
          before() 在被選元素前插入內容
          clone() 生成被選元素的副本
          css() 為被選元素設置或返回一個或多個樣式屬性
          detach() 移除被選元素(保留數據和事件)
          empty() 從被選元素移除所有子節點和內容
          hasClass() 檢查被選元素是否包含指定的 class 名稱
          height() 設置或返回被選元素的高度
          html() 設置或返回被選元素的內容
          innerHeight() 返回元素的高度(包含 padding,不包含 border)
          innerWidth() 返回元素的寬度(包含 padding,不包含 border)
          insertAfter() 在被選元素后插入 HTML 元素
          insertBefore() 在被選元素前插入 HTML 元素
          offset() 設置或返回被選元素的偏移坐標(相對于文檔)
          offsetParent() 返回第一個定位的祖先元素
          outerHeight() 返回元素的高度(包含 padding 和 border)
          outerWidth() 返回元素的寬度(包含 padding 和 border)
          position() 返回元素的位置(相對于父元素)
          prepend() 在被選元素的開頭插入內容
          prependTo() 在被選元素的開頭插入 HTML 元素
          prop() 設置或返回被選元素的屬性/值
          remove() 移除被選元素(包含數據和事件)
          removeAttr() 從被選元素移除一個或多個屬性
          removeClass() 從被選元素移除一個或多個類
          removeProp() 移除通過 prop() 方法設置的屬性
          replaceAll() 把被選元素替換為新的 HTML 元素
          replaceWith() 把被選元素替換為新的內容
          scrollLeft() 設置或返回被選元素的水平滾動條位置
          scrollTop() 設置或返回被選元素的垂直滾動條位置
          text() 設置或返回被選元素的文本內容
          toggleClass() 在被選元素中添加/移除一個或多個類之間切換
          unwrap() 移除被選元素的父元素
          val() 設置或返回被選元素的屬性值(針對表單元素)
          width() 設置或返回被選元素的寬度
          常用實例:

          三級菜單展示

          $(this).next().removeClass('hide').parent().siblings().find('.items').addClass('hide')
          1
          直接操作css屬性

          // 兩個參數設置屬性
          $('#p1').css('font-size','24px')
          // 一個參數獲取屬性
          $('#p1').css('font-size')

          // 一次設置多個屬性
          $('#p1').css({"border":"1px solid black","color":"blue"})
          1
          2
          3
          4
          5
          6
          7
          位置操作

          // 不加參數獲取位置參數
          $(".c3").offset()
          // 加參數設置位置參數
          $(".c3").offset({top:284,left:400})

          // position只能獲取值,不能設置值

          // scrollTop獲取當前滾動條偏移量
          $('window').scrollTop();
          $('window').scrollTop(0);  // 設置滾動條偏移量
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          文本操作

          text() html() 不加參數獲取值,加參數設置值
          val() 不加參數獲取值,加參數設置值
          1
          2
          屬性操作

          // 獲取文本屬性
          $('#d1').attr('s1')  // 獲取屬性值
          $('#d1').attr('s1','haha')  // 設置屬性值
          $('#d1').attr({'num':50,'taidi':'gay'})  // 設置多個屬性
          $('#d1').removeAttr('taidi')  // 刪除一個屬性

          // 獲取check與radio標簽的checked屬性
          $('#i1').prop('checked')
          $('#i1').prop('checked',true)
          1
          2
          3
          4
          5
          6
          7
          8
          9
          文檔處理

          // 標簽內部尾部追加元素
          $('#d1').append(pEle)
          $pEle.appendTo($('#d1'))

          // 標簽內部頭部添加元素
          $('#d1').prepend(pEle)
          $pEle.prependTo($('#d1'))

          // 標簽外部下面添加元素
          $(A).after(B)// 把B放到A的后面
          $(A).insertAfter(B)// 把A放到B的后面

          // 標簽外部上面添加元素
          $(A).before(B)// 把B放到A的前面
          $(A).insertBefore(B)// 把A放到B的前面

          // 替換標簽
          replaceWith()  // 什么被什么替換
          replaceAll()  // 拿什么替換什么

          // 克隆事例
          <button id="b2">屠龍寶刀,點擊就送</button>
          // clone方法加參數true,克隆標簽并且克隆標簽帶的事件
            $("#b2").on("click", function () {
              $(this).clone(true).insertAfter(this);  // true參數
            });
          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
          表單篩選器
          選擇器 實例 選取
          :input $(":input") 所有 input 元素
          :text $(":text") 所有帶有 type=“text” 的 input 元素
          :password $(":password") 所有帶有 type=“password” 的 input 元素
          :checkbox $(":checkbox") 所有帶有 type=“checkbox” 的 input 元素
          :submit $(":submit") 所有帶有 type=“submit” 的 input 元素
          :reset $(":reset") 所有帶有 type=“reset” 的 input 元素
          :button $(":button") 所有帶有 type=“button” 的 input 元素
          :image $(":image") 所有帶有 type=“image” 的 input 元素
          :file $(":file") 所有帶有 type=“file” 的 input 元素
          :enabled $(":enabled") 所有啟用的 input 元素
          :disabled $(":disabled") 所有禁用的 input 元素
          :selected $(":selected") 所有選定的 input 元素
          :checked $(":checked") 所有選中的 input 元素
          // 針對表單內的標簽
          $('input[type="text"]')
          // 簡化寫法
          $(':text')

          // 找到所有被選中的checkbox
          $(':checkbox')  // 注意select框中默認selected標簽也會被找到
          $('input:checkbox')
          1
          2
          3
          4
          5
          6
          7
          8
          遍歷方法
          方法 描述
          add() 把元素添加到匹配元素的集合中
          children() 返回被選元素的所有直接子元素
          closest() 返回被選元素的第一個祖先元素
          contents() 返回被選元素的所有直接子元素(包含文本和注釋節點)
          each() 為每個匹配元素執行函數
          filter() 把匹配元素集合縮減為匹配選擇器或匹配函數返回值的新元素
          find() 返回被選元素的后代元素
          first() 返回被選元素的第一個元素
          is() 根據選擇器/元素/jQuery 對象檢查匹配元素集合,如果存在至少一個匹配元素,則返回 true
          last() 返回被選元素的最后一個元素
          next() 返回被選元素的后一個同級元素
          nextAll() 返回被選元素之后的所有同級元素
          nextUntil() 返回介于兩個給定參數之間的每個元素之后的所有同級元素
          not() 從匹配元素集合中移除元素
          offsetParent() 返回第一個定位的父元素
          parent() 返回被選元素的直接父元素
          parents() 返回被選元素的所有祖先元素
          parentsUntil() 返回介于兩個給定參數之間的所有祖先元素
          prev() 返回被選元素的前一個同級元素
          prevAll() 返回被選元素之前的所有同級元素
          prevUntil() 返回介于兩個給定參數之間的每個元素之前的所有同級元素
          siblings() 返回被選元素的所有同級元素 Returns all sibling elements of the selected element
          slice() 把匹配元素集合縮減為指定范圍的子集
          each() 方法為每個匹配元素規定要運行的函數。
          $.each(array,function(index){
            console.log(array[index])
          })
          $.each(array,function(){
            console.log(this);
          })
          // 支持簡寫
          $divEles.each(function(){
            console.log(this)  // 標簽對象
          })
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          jQuery鏈式操作
          python代碼詮釋鏈式調用,其實就是在調用方法之后講對象再次返回

          <div>
          <p>p1</p>
          <p>p2</p>
          </div>
          $('div>p').first().addclass('c1').next().addclass('c2');
          1
          2
          3
          4
          5
          jQuery 事件
          事件處理程序指的是當 HTML 中發生某些事件時所調用的方法。

          $(document).ready()
          $(document).ready() 方法允許我們在文檔完全加載完后執行函數。為了防止網頁還沒加載完,js代碼就已經執行,通常利用下面兩種方式來書寫js代碼。

          $(document).ready(function(){
          // 在這里寫你的JS代碼...
          })

          網頁最后
          $(function(){
          // 在這里寫你的代碼
          })
          1
          2
          3
          4
          5
          6
          7
          8
          click()
          click() 方法是當按鈕點擊事件被觸發時會調用一個函數。

          在下面的實例中,當點擊事件在某個<p> 元素上觸發時,隱藏當前的 <p> 元素:

          $("p").click(function(){ 
            $(this).hide(); 
          });
          1
          2
          3
          dblclick()
          當雙擊元素時,會發生 dblclick 事件。

          $("p").dblclick(function(){ 
            $(this).hide(); 
          });
          1
          2
          3
          mouseenter()
          當鼠標指針穿過元素時,會發生 mouseenter 事件。

          $("#p1").mouseenter(function(){ 
            alert("鼠標經過了!"); 
          });
          1
          2
          3
          mouseleave()
          當鼠標指針離開元素時,會發生 mouseleave 事件。

          $("#p1").mouseleave(function(){ 
            alert("鼠標離開了!"); 
          });
          1
          2
          3
          mousedown()
          當鼠標指針移動到元素上方,并按下鼠標按鍵時,會發生 mousedown 事件。

          $("#p1").mousedown(function(){ 
            alert("鼠標按下!"); 
          });
          1
          2
          3
          mouseup()
          當在元素上松開鼠標按鈕時,會發生 mouseup 事件。

          ouseup(function(){ 
            alert("鼠標松開!"); 
          });
          1
          2
          3
          hover()
          hover()方法用于模擬光標懸停事件。當鼠標移動到元素上時,會觸發指定的第一個函數(mouseenter);當鼠標移出這個元素時,會觸發指定的第二個函數(mouseleave)。

          $("#p1").hover(function(){ 
            alert("你的光標懸停!"); 
            }, 
            function(){ 
            alert("你的光標已經離開!"); 
          });
          1
          2
          3
          4
          5
          6
          focus()
          當元素獲得焦點時,發生 focus 事件。

          $("input").focus(function(){ 
            $(this).css("background-color","#eee"); 
          });
          1
          2
          3
          blur()
          當元素失去焦點時,發生 blur 事件。

          $("input").blur(function(){ 
            $(this).css("background-color","#eee"); 
          });
          1
          2
          3
          input()
          input實時監聽,輸入內容時發生 input 事件

           $('#i1').on('input',function () {
                  console.log($(this).val())
              });
          1
          2
          3
          取消標簽默認的事件
          利用preventDefault()
          $('input').click(function (e) {
                  alert(123);
                  e.preventDefault();  
              });
          直接返回false
          $('input').click(function (e) {
                  alert(123);
                  return false;
              });
            
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          事件冒泡
          iv>p>span  // 三者均綁定點擊事件
          $("span").click(function (e) {
                  alert("span");
                  e.stopPropagation();  // 阻止事件冒泡
              });
          1
          2
          3
          4
          5
          事件委托
          <button>按鈕</button>
          <script src="jQuery-3.3.1.js"></script>
          <script>
              $('body').on('click','button',function () {
                  alert(123)
              })
          </script>
          1
          2
          3
          4
          5
          6
          7
          jQuery自帶的動畫效果
          下面的表格列出了用于創建動畫效果的 jQuery 方法。

          方法 描述
          delay() 對被選元素的所有排隊函數(仍未運行)設置延遲
          dequeue() 移除下一個排隊函數,然后執行函數
          fadeIn() 逐漸改變被選元素的不透明度,從隱藏到可見
          fadeOut() 逐漸改變被選元素的不透明度,從可見到隱藏
          fadeTo() 把被選元素逐漸改變至給定的不透明度
          fadeToggle() 在 fadeIn() 和 fadeOut() 方法之間進行切換
          finish() 對被選元素停止、移除并完成所有排隊動畫
          hide() 隱藏被選元素
          queue() 顯示被選元素的排隊函數
          show() 顯示被選元素
          slideDown() 通過調整高度來滑動顯示被選元素
          slideToggle() slideUp() 和 slideDown() 方法之間的切換
          slideUp() 通過調整高度來滑動隱藏被選元素
          stop() 停止被選元素上當前正在運行的動畫
          toggle() hide() 和 show() 方法之間的切換
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、網站建設 平面設計服務。

          微信小程序--實現canvas繪圖并且可以復盤回看

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          目錄結構:



          index.wxml:

          <view class="canvasBox">
            <canvas canvas-id="myCanvas" class="myCanvas" catchtouchstart='canvasStart' catchtouchmove='canvasMoving'></canvas>
          </view>
          <view class="btn">
            <button type="warn" bindtap='drawPen'>畫筆</button>
            <button type="primary" bindtap='clearCanvas'>清空畫板</button>
            <button type="warn" bindtap='clearLine'>橡皮擦</button>
            <button style='background:#000;color:#fff;' bindtap="black">黑色</button>
            <button style='background:yellow;color:#000;' bindtap="yellow">黃色</button>
            <button style='background:red;color:#fff;' bindtap="red">紅色</button>
            <button style='background:blue;color:#fff;' bindtap="blue">藍色</button>
            <button style='background:green;color:#fff;' bindtap="green">綠色</button>
            <button type="warn" bindtap="startRecording">開始錄制</button>
            <button type="primary" bindtap='rePlay'>復盤</button>
            <button></button>
          </view>
          index.wxss:

          .canvasBox{
            position: relative;
            top:0;
            left:0;
            width: 750rpx;
            height:800rpx;
            background:#eee;
          }
          .canvasBox .myCanvas{
            width: 100%;
            height:100%;
            position: absolute;
            top:0;
            left:0;
          }
           
          .btn{
            width: 750rpx;
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
          }
          .btn button{
            width: 180rpx;
            font-size: 24rpx;
          }
          index.js:

          //index.js
          //獲取應用實例
          import {hisData} from "../../utils/historyOperation.js";
          const app = getApp()
          var moveToX = 0, moveToY = 0, lineToX = 0, lineToY = 0;
          var context = null;
          var isStart = false;
          var date;
          var startDate;//開始時刻
          var penType = "drawPen";
          var colorStr = "#000";
          var operationType = "mapping";
          Page({
            data: {
              
            },
            
            canvasStart:function(e){
              var x = Math.floor(e.touches[0].clientX);
              var y = Math.floor(e.touches[0].clientY);
              date = new Date();
              moveToX = x;
              moveToY = y;
              operationType = "mapping";
              if(penType === "clearPen"){
                operationType = "clearLine";
              }
              if (isStart) {
                hisData.hisDataArr.push({
                  time: date.getTime() - startDate,
                  operation: operationType,
                  lineArr: {
                    startX: moveToX,
                    startY: moveToY,
                    currentX: x,
                    currentY: y,
                    z: 1,
                    colorStr:colorStr
                  }
                })
              }
            },
            //繪制線條
            canvasMoving:function(e){
              date = new Date();
              var x = Math.floor(e.changedTouches[0].clientX);
              var y = Math.floor(e.changedTouches[0].clientY);
              lineToX = x;
              lineToY = y;
              if(penType === "clearPen"){
                operationType = "clearLine";
                context.clearRect(x-12, y-12, 24, 24);
                context.draw(true);
              }else{
                operationType = "mapping";
                context.setStrokeStyle(colorStr);
                context.moveTo(moveToX, moveToY);
                context.lineTo(lineToX, lineToY);
              }
              if (isStart) {
                hisData.hisDataArr.push({
                  time: date.getTime() - startDate,
                  operation: operationType,
                  lineArr: {
                    startX: moveToX,
                    startY: moveToY,
                    currentX: lineToX,
                    currentY: lineToY,
                    z: 1,
                    colorStr: colorStr
                  }
                })
              }
              moveToX = lineToX;
              moveToY = lineToY;
              context.stroke();
              context.draw(true);
            },
            
            clearCanvas:function(){
              context.clearRect(0,0,375,400);
              context.draw(true);
              date = new Date();//記錄當前操作時刻
              operationType = "clearCanvas";
              if(isStart){
                hisData.hisDataArr.push({
                  time: date.getTime() - startDate,
                  operation: operationType,
                  lineArr: {
                    startX: -1,
                    startY: -1,
                    currentX: -1,
                    currentY: -1,
                    z: 0,
                    colorStr: colorStr
                  }
                })
              }
            },
            
            drawPen:function(){
              penType = "drawPen";
            },
            clearLine:function(){
              penType = "clearPen";
            },
            black:function(){
              colorStr = "#000";
            },
            yellow: function () {
              colorStr = "yellow";
            },
            red: function () {
              colorStr = "red";
            },
            blue: function () {
              colorStr = "blue";
            },
            green: function () {
              colorStr = "green";
            },
            startRecording:function(){
              isStart = true;
              date = new Date();
              startDate = date.getTime();
            },
            rePlay:function(){
              wx.navigateTo({
                url: '../replay/replay',
              })
            },
            onLoad: function () {
              isStart = false;
              context = wx.createCanvasContext('myCanvas');
              context.beginPath();
              context.setStrokeStyle('#000');
              context.setLineWidth(5);
              context.setLineCap('round');
              context.setLineJoin('round');
            }
          })
          historyOperation.js:該文件用來保存歷史操作,以便復盤

          const hisData = {
            hisDataArr:[
              {
                time:0,//操作時間
                /**
                 * 操作類型
                 * 繪圖:mapping
                 * 拖動球員:moveplayer
                 * 清除畫布:clearCanvas
                 * 橡皮擦:clearLine
                 */
                operation:"mapping",//操作類型
                /**
                 * 繪制路徑
                 * startX:開始x坐標
                 * startY:開y縱坐標
                 * currentX:目標位置的 x 坐標
                 * currentY:目標位置的 y 坐標
                 * z:1代表畫線時鼠標處于move狀態,0代表處于松開狀態
                 * colorStr:線的填充顏色
                 */
                lineArr: {    //繪制路徑
                  startX:0,
                  startY:0,
                  currentX:0,
                  currentY:0,
                  z:0,
                  colorStr:"#000"
                }
              }
            ]
          };
           
          export {hisData};
          復盤:

          reply.wxml:

          <!--pages/replay/replay.wxml-->
          <view class="replayBox">
            <canvas canvas-id='myCanvas' class="myCanvas"></canvas>
          </view>
          <button type="warn" bindtap="start">開始</button>
          reply.wxss:

          /* pages/replay/replay.wxss */
          .replayBox{
            position:relative;
            width: 750rpx;
            height:800rpx;
            background: #eee;
          }
           
          .replayBox .myCanvas{
            position: absolute;
            top:0;
            left:0;
            width:100%;
            height:100%;
          }
           
          reply.js:

          // pages/replay/replay.js
          import {hisData} from "../../utils/historyOperation.js";
          var startDate;
          var date;
          var curTime;
          var context = null;
          var timer = null;
          Page({
           
            /**
             * 頁面的初始數據
             */
            data: {
           
            },
            start:function(){
              context.clearRect(0, 0, 375, 400);
              clearInterval(timer);
              date = new Date();
              startDate = date.getTime();
              var i = 0;
              var that = this;
              var len = hisData.hisDataArr.length;
              timer = setInterval(function(){
                date = new Date();
                curTime = date.getTime() - startDate;
                if (curTime >= hisData.hisDataArr[i].time){
                  switch (hisData.hisDataArr[i].operation) {
                    case "mapping":
                      context.setStrokeStyle(hisData.hisDataArr[i].lineArr.colorStr);
                      context.moveTo(hisData.hisDataArr[i].lineArr.startX, hisData.hisDataArr[i].lineArr.startY);
                      context.lineTo(hisData.hisDataArr[i].lineArr.currentX, hisData.hisDataArr[i].lineArr.currentY);
                      context.stroke();
                      context.draw(true);
                      break;
                    case "clearCanvas":
                      context.clearRect(0, 0, 375, 400);
                      context.draw(true);
                      break;
                    case "clearLine":
                      context.clearRect(hisData.hisDataArr[i].lineArr.currentX-12, hisData.hisDataArr[i].lineArr.currentY-12, 24, 24);
                      context.draw(true);
                      break;
                  }
                  i++;
                }
                if(i >= len){
                  clearInterval(timer);
                }
              },2);
            },
            /**
             * 生命周期函數--監聽頁面加載
             */
            onLoad: function (options) {
              context = wx.createCanvasContext('myCanvas');
              context.beginPath();
              context.setStrokeStyle('#000');
              context.setLineWidth(3);
              context.setLineCap('round');
              context.setLineJoin('round');
            }
          })
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、網站建設 、平面設計服務

          后端人員如何快速上手css(flex布局

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          網頁布局(layout)是 CSS 的一個重點應用。畢竟簡單的樣式不能總依賴前端人員。
          布局的傳統解決方案,基于盒狀模型,依賴 display 屬性 + position屬性 + float屬性。它對于那些特殊布局非常不方便,比如,垂直居中就不容易實現。

          2009年,W3C 提出了一種新的方案----Flex 布局,可以簡便、完整、響應式地實現各種頁面布局。目前,它已經得到了所有瀏覽器的支持,這意味著,現在就能很安全地使用這項功能。

          Flex 是 Flexible Box 的縮寫,意為"彈性布局",用來為盒狀模型提供最大的靈活性。

          采用 Flex 布局的元素,稱為 Flex 容器(flex container),簡稱"容器"。它的所有子元素自動成為容器成員,稱為 Flex 項目(flex item),簡稱"項目"。


          容器默認存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做main start,結束位置叫做main end;交叉軸的開始位置叫做cross start,結束位置叫做cross end。

          項目默認沿主軸排列。單個項目占據的主軸空間叫做main size,占據的交叉軸空間叫做cross size。

          先說第一個屬性flex-direction 屬性決定主軸的方向(即項目的排列方向)。
          .box {
          flex-direction: row | row-reverse | column | column-reverse;
          }
          row(默認值):主軸為水平方向,起點在左端。
          row-reverse:主軸為水平方向,起點在右端。
          column:主軸為垂直方向,起點在上沿。
          column-reverse:主軸為垂直方向,起點在下沿。
          廢話少說,立刻上代碼,驗證下。

          row:

          眾所周知,h1和p都是塊級元素,都會縱向排列,一旦采用 Flex 布局,就以x和y軸為基礎排序,
          column:

          不但模糊了塊級元素和行內元素的區別,而且左右的排序也很靈活。
          row-reverse:

          flex-wrap屬性
          默認情況下,項目都排在一條線(又稱"軸線")上。flex-wrap屬性定義,如果一條軸線排不下,就會換行。
          .box{
          flex-wrap: nowrap | wrap | wrap-reverse;
          }
          (1)nowrap(默認):不換行。
          (2)wrap:換行,第一行在上方。
          (3)wrap-reverse:換行,第一行在下方。
          wrap:

          雖然他換行了,但是每行的元素是不是靠的太近了
          在這時候就能用到
          justify-content屬性
          justify-content屬性定義了項目在主軸上的對齊方式。
          .box {
          justify-content: flex-start | flex-end | center | space-between | space-around;
          }
          它可能取5個值,具體對齊方式與軸的方向有關。下面假設主軸為從左到右。

          flex-start:(默認值):左對齊
          flex-end:右對齊
          center: 居中
          space-between:兩端對齊,項目之間的間隔都相等。
          space-around:每個項目兩側的間隔相等。所以,項目之間的間隔比項目與邊框的間隔大一倍。

          space-between:

          但是還是有點不對勁,原來沒有垂直居中。
          align-items屬性就出來了
          align-items屬性定義項目在交叉軸上如何對齊。
          .box {
          align-items: flex-start | flex-end | center | baseline | stretch;
          }
          它可能取5個值。具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。
          flex-start:交叉軸的起點對齊。
          flex-end:交叉軸的終點對齊。
          center:交叉軸的中點對齊。
          baseline: 項目的第一行文字的基線對齊。
          stretch(默認值):如果項目未設置高度或設為auto,將占滿整個容器的高度。

          還有很多屬性可以靈活的調整頁面的排版,我只舉例最簡單的幾種排版。
          沒有float,沒有position,也沒有行和塊。只要知道x軸和y軸就能輕松布局。
          如果想了解flex布局,可以看一下這位大佬的博客:
          語法篇:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
          實戰篇:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html


          前端開發——NodeJs學習

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          NodeJs基礎
          nodejs的本質:不是一門新的編程語言,nodejs是javascript運行在服務端的運行環境,編程語言還是javascript

          global模塊-全局變量
          Node.js 中的全局對象是 global, 類似于瀏覽器中的window

          常用的global屬性

          console: 用于打印日志
          setTimeout/clearTimeout: 設置清除延時器
          setInterval/clearInterval: 設置清除定時器

          __dirname: 當前文件的路徑,不包括文件名
          __filename: 獲取當前文件的路徑,包括文件名

          //與模塊化相關的,模塊化的時候會用到
          require
          exports
          module

          除了global模塊中的內容可以直接使用,其他模塊都是需要加載的。
          其他模塊不是全局的,不能直接使用。因此需要導入才能使用。
          fs模塊
          fileSystem-- 文件系統,提供了一系列操作文件的API接口,可以方便我讀寫文件

          讀取文件
          語法:fs.readFile(path[, options], callback)

          方式一:不傳編碼參數

          //參數1: 文件的名字
          //參數2: 讀取文件的回調函數
            //參數1:錯誤對象,如果讀取失敗,err會包含錯誤信息,如果讀取成功,err是null
            //參數2:讀取成功后的數據(是一個Buffer對象)
          fs.readFile("data.txt", function(err, data){
            console.log(err);
            console.log(data);
            // 可以通過data.toString() 把二進制數據轉成文本,當然前提是讀取的文件本來就是文本,如果是圖片獲取的二進制就無法轉換成文本
          });

          方式二:傳編碼參數

          //參數1: 文件的路徑
          //參數2: 編碼,如果設置了,返回一個字符串,如果沒有設置,會返回一個buffer對象
          //參數3: 回調函數
          fs.readFile("data.txt", "utf8",function(err, data){
            console.log(err);
            console.log(data);
          });

          關于Buffer對象

          1. Buffer對象是Nodejs用于處理二進制數據的。
          2. 其實任意的數據在計算機底層都是二進制數據,因為計算機只認識二進制。
          3. 所以讀取任意的文件,返回的結果都是二進制數據,即Buffer對象
          4. Buffer對象可以調用toString()方法轉換成字符串。

          寫文件
          語法:fs.writeFile(file, data[, options], callback)

          //參數1:寫入的文件名(如果文件不存在,會自動創建)
          //參數2:寫入的文件內容(注意:寫入的內容會覆蓋以前的內容)
          //參數3:寫文件后的回調函數
          fs.writeFile("2.txt", "hello world, 我是一個中國人", function(err){
            if(err) {
              return console.log("寫入文件失敗", err);
            }
            console.log("寫入文件成功");
          });
          1
          2
          3
          4
          5
          6
          7
          8
          9
          注意:

          寫文件的時候,會把原來的內容給覆蓋掉
          追加文件
          語法:fs.appendFile(path, data[, options], callback)

          //參數1:追加的文件名(如果文件不存在,會自動創建)
          //參數2:追加的文件內容(注意:寫入的內容會覆蓋以前的內容)
          //參數3:追加文件后的回調函數
          fs.appendFile("2.txt", "我是追加的內容", function(err){
            if(err) {
              return console.log("追加文件內容失敗");
            }
            console.log("追加文件內容成功");
          })


          思考:如果沒有appendFile,通過readFile與writeFile應該怎么實現?

          文件同步與異步的說明
          fs中所有的文件操作,都提供了異步和同步兩種方式

          異步方式:不會阻塞代碼的執行
          同步方式:會阻塞代碼的執行
          //同步方式
          console.log(111);
          var result = fs.readFileSync("2.txt", "utf-8");
          console.log(result);
          console.log(222);

          總結:同步操作使用雖然簡單,但是會影響性能,因此盡量使用異步方法,尤其是在工作過程中。

          stream
          stream是Node.js提供的又一個僅在服務區端可用的模塊,目的是支持“流”這種數據結構。

          什么是流?流是一種抽象的數據結構。想象水流,當在水管中流動時,就可以從某個地方(例如自來水廠)源源不斷地到達另一個地方(比如你家的洗手池)。我們也可以把數據看成是數據流,比如你敲鍵盤的時候,就可以把每個字符依次連起來,看成字符流。這個流是從鍵盤輸入到應用程序,實際上它還對應著一個名字:標準輸入流(stdin)。

          如果應用程序把字符一個一個輸出到顯示器上,這也可以看成是一個流,這個流也有名字:標準輸出流(stdout)。流的特點是數據是有序的,而且必須依次讀取,或者依次寫入,不能像Array那樣隨機定位。

          有些流用來讀取數據,比如從文件讀取數據時,可以打開一個文件流,然后從文件流中不斷地讀取數據。有些流用來寫入數據,比如向文件寫入數據時,只需要把數據不斷地往文件流中寫進去就可以了。

          在Node.js中,流也是一個對象,我們只需要響應流的事件就可以了:data事件表示流的數據已經可以讀取了,end事件表示這個流已經到末尾了,沒有數據可以讀取了,error事件表示出錯了。

          下面是一個從文件流讀取文本內容的示例:

          'use strict';

          var fs = require('fs');

          // 打開一個流:
          var rs = fs.createReadStream('sample.txt', 'utf-8');

          rs.on('data', function (chunk) {
              console.log('DATA:')
              console.log(chunk);
          });

          rs.on('end', function () {
              console.log('END');
          });

          rs.on('error', function (err) {
              console.log('ERROR: ' + err);
          });

          要注意,data事件可能會有多次,每次傳遞的chunk是流的一部分數據。

          要以流的形式寫入文件,只需要不斷調用write()方法,最后以end()結束:

          'use strict';

          var fs = require('fs');

          var ws1 = fs.createWriteStream('output1.txt', 'utf-8');
          ws1.write('使用Stream寫入文本數據...\n');
          ws1.write('END.');
          ws1.end();

          var ws2 = fs.createWriteStream('output2.txt');
          ws2.write(new Buffer('使用Stream寫入二進制數據...\n', 'utf-8'));
          ws2.write(new Buffer('END.', 'utf-8'));
          ws2.end();


          所有可以讀取數據的流都繼承自stream.Readable,所有可以寫入的流都繼承自stream.Writable。

          pipe
          就像可以把兩個水管串成一個更長的水管一樣,兩個流也可以串起來。一個Readable流和一個Writable流串起來后,所有的數據自動從Readable流進入Writable流,這種操作叫pipe。

          在Node.js中,Readable流有一個pipe()方法,就是用來干這件事的。

          讓我們用pipe()把一個文件流和另一個文件流串起來,這樣源文件的所有數據就自動寫入到目標文件里了,所以,這實際上是一個復制文件的程序:

          'use strict';

          var fs = require('fs');

          var rs = fs.createReadStream('sample.txt');
          var ws = fs.createWriteStream('copied.txt');

          rs.pipe(ws);

          默認情況下,當Readable流的數據讀取完畢,end事件觸發后,將自動關閉Writable流。如果我們不希望自動關閉Writable流,需要傳入參數:

          readable.pipe(writable, { end: false });
          1
          path模塊
          路徑操作的問題
          具體的說明可以參考 NodeJs學習.md

          在讀寫文件的時候,文件路徑可以寫相對路徑或者絕對路徑

          //data.txt是相對路徑,讀取當前目錄下的data.txt, 相對路徑相對的是指向node命令的路徑
          //如果node命令不是在當前目錄下執行就會報錯, 在當前執行node命令的目錄下查找data.txt,找不到
          fs.readFile("data.txt", "utf8", function(err, data) {
            if(err) {
              console.log("讀取文件失敗", err);
            }

            console.log(data);
          });

          相對路徑:相對于執行node命令的路徑

          絕對路徑:__dirname: 當前文件的目錄,__filename: 當前文件的目錄,包含文件名

          path模塊的常用方法
          關于路徑,在linux系統中,路徑分隔符使用的是/,但是在windows系統中,路徑使用的\

          在我們拼寫路徑的時候會帶來很多的麻煩,經常會出現windows下寫的代碼,在linux操作系統下執行不了,path模塊就是為了解決這個問題而存在的。

          常用方法:

          path.join();//拼接路徑

          //windows系統下
          > path.join("abc","def","gg", "index.html")
          "abc\def\gg\a.html"

          //linux系統下
          > path.join("abc","def","gg", "index.html")
          'abc/def/gg/index.html'

          http模塊
          創建服務器步驟

          // 移入http模塊
          const http = require('http')
          // 調用創建http 服務器的方法
          const server = http.createServe()
          // 給服務器注冊request事件監聽,每次瀏覽器像服務器發送請求的時候都會被監聽到
          server.on('request', function(request, response){
              // request 瀏覽器請求的數據,包括請求方式method 請求的地址 url等
              // response 瀏覽器的響應,可以設置響應頭、響應體、響應狀態碼
              const method = request.method
              const url = request.url
              
              // 設置響應的狀態碼
              response.StatusCode = 404
              // 設置響應的頭
              response.setHeader('Content-Type', 'text/html');
              // 設置響應體內容,write可以調用多次
              response.write('hello world!')
              // 響應結束
              response.end()
              
              // 如果在end(content),這樣的寫法相當于是讓write和end的合寫
              response.end('hello world!')
          })
          // 給服務器設置監聽,相當于啟動服務器
          server.listen(8888,function(){
              console.log('服務器啟動成功')
          })

          // 簡寫方式

          http.createServer((req,res) => {
              ....
          }).listen(8888,() => {
              ....
          })

          詳細說明

          給服務器注冊request事件,只要服務器接收到了客戶端的請求,就會觸發request事件
          request事件有兩個參數,request表示請求對象,可以獲取所有與請求相關的信息,response是響應對象,可以獲取所有與響應相關的信息。
          服務器監聽的端口范圍為:1-65535之間,推薦使用3000以上的端口,因為3000以下的端口一般留給系統使用
          response對象詳解
          常見的屬性和方法:

          res.write(data): 給瀏覽器發送請求體,可以調用多次,從而提供連續的請求體
          res.end();   通知服務器,所有響應頭和響應主體都已被發送,即服務器將其視為已完成。
          res.end(data); 結束請求,并且響應一段內容,相當于res.write(data) + res.end()
          res.statusCode: 響應的的狀態碼 200 404 500
          res.statusMessage: 響應的狀態信息, OK Not Found ,會根據statusCode自動設置。
          res.setHeader(name, value); 設置響應頭信息, 比如content-type
          res.writeHead(statusCode, statusMessage, options); 設置響應頭,同時可以設置狀態碼和狀態信息。
          1
          2
          3
          4
          5
          6
          7
          注意:必須先設置響應頭,才能設置響應。

          實現靜態WEB服務器
          服務器響應首頁
          注意:瀏覽器中輸入的URL地址,僅僅是一個標識,不與服務器中的目錄一致。也就是說:返回什么內容是由服務端的邏輯決定
          server.on('request', function(req, res) {
            var url = req.url
            if(url === '/') {
              fs.readFile('./index.html', function(err, data) {
                if(err) {
                  return res.end('您訪問的資源不存在~')
                }

                res.end(data)
              })
            }
          })

          根據根據不同url,響應不同文件
          content-type設置-MIME類型
          MIME(Multipurpose Internet Mail Extensions)多用途Internet郵件擴展類型 是一種表示文檔性質和格式的標準化方式
          瀏覽器通常使用MIME類型(而不是文件擴展名)來確定如何處理文檔;因此服務器將正確的MIME類型附加到響應對象的頭部是非常重要的
          MIME類型的通用處理-mime模塊
          作用:獲取文件的MIME類型
          安裝:npm i mime
          var mime = require('mime')

          // 獲取路徑對應的MIME類型
          mime.getType('txt')                    // ? 'text/plain'
          // 根據MIME獲取到文件后綴名
          mime.getExtension('text/plain')        // ? 'txt'
          1
          2
          3
          4
          5
          6
          有了這個模塊我們就可以把設置響應頭的代碼改寫成下面

          // mime 不僅可以只寫一個后綴名,還可以通過url來解析出后綴名來,因此這里可以直接寫url
          response.setHeader('content-type',mime.getType(request.url))
          1
          2
          npm - Node包管理工具
          初始化包
          npm init;    //這個命令用于初始化一個包,創建一個package.json文件,我們的項目都應該先執行npm init
          npm init -y;  //快速的初始化一個包, 不能是一個中文名
          1
          2
          安裝包
          npm install 包名;  //安裝指定的包名的版本到項目中
          npm install 包名@版本號;  //安裝指定包的指定版本

          npm i 包名; //簡寫

          卸載包
          npm uninstall 包名;  //卸載已經安裝的包
          1
          清除緩存
          npm cache clean -f // 如果npm安裝失敗了,可以用這個命令來清除緩存
          1
          package.json文件
          package.json文件,包(項目)描述文件,用來管理組織一個包(項目),它是一個純JSON格式的。

          作用:描述當前項目(包)的信息,描述當前包(項目)的依賴項
          如何生成:npm init或者npm init -y
          作用
          作為一個標準的包,必須要有package.json文件進行描述
          一個項目的node_modules目錄通常都會很大,不用拷貝node_modules目錄,可以通過package.json文件配合npm install直接安裝項目所有的依賴項
          描述內容
          {
            "name": "03-npm",  //描述了包的名字,不能有中文
            "version": "1.0.0",  //描述了包的的版本信息, x.y.z  如果只是修復bug,需要更新Z位。如果是新增了功能,但是向下兼容,需要更新Y位。如果有大變動,向下不兼容,需要更新X位。
            "description": "", //包的描述信息
            "main": "index.js", //入口文件(模塊化加載規則的時候詳細的講)
            "scripts": {  //配置一些腳本,在vue的時候會用到,現在體會不到
              "test": "echo \"Error: no test specified\" && exit 1"
            },
            "keywords": [],  //關鍵字(方便搜索)
            "author": "",  //作者的信息
            "license": "ISC",  //許可證,開源協議
            "dependencies": {   //重要,項目的依賴, 方便代碼的共享  通過 npm install可以直接安裝所有的依賴項
              "bootstrap": "^3.3.7",
              "jquery": "^3.3.1"
            }
          }

          注意:一個合法的package.json,必須要有name和version兩個屬性

          本地安裝和全局安裝
          有兩種方式用來安裝 npm 包:本地安裝和全局安裝。選用哪種方式來安裝,取決于你如何使用這個包。

          全局安裝:如果你想將其作為一個命令行工具,那么你應該將其安裝到全局。這種安裝方式后可以讓你在任何目錄下使用這個命令。比如less命令,webpack命令,hcc-md命令 。
          本地安裝:如果你自己的模塊依賴于某個包,并通過 Node.js 的 require 加載,那么你應該選擇本地安裝,這種方式也是 npm install 命令的默認行為。
          // 全局安裝,會把npm包安裝到C:\Users\HUCC\AppData\Roaming\npm目錄下,作為命令行工具使用
          npm install -g 包名;

          //本地安裝,會把npm包安裝到當前項目的node_modules文件中,作為項目的依賴
          npm install 包名;  

          常見的命令行工具
          nrm
          nrm:npm registry manager(npm倉庫地址管理工具)
          安裝:npm i -g nrm
          # 帶*表示當前正在使用的地址

          # 查看倉庫地址列表
          nrm ls

          # 切換倉庫地址
          nrm use taobao

          nodemon 自動重啟
          作用:監視到js文件修改后,自動重啟node程序
          安裝:npm i -g nodemon
          使用:nodemon app.js 運行node程序
          模塊化(module)
          基本概念
          在nodejs中,應用由模塊組成,nodejs中采用commonJS模塊規范。

          一個js文件就是一個模塊
          每個模塊都是一個獨立的作用域,在這個而文件中定義的變量、函數、對象都是私有的,對其他文件不可見。
          node中模塊分類
          1 核心模塊
          由 node 本身提供,不需要單獨安裝(npm),可直接引入使用
          2 第三方模塊
          由社區或個人提供,需要通過npm安裝后使用
          3 自定義模塊
          由我們自己創建,比如:tool.js 、 user.js
          核心模塊
          fs:文件操作模塊
          http:網絡操作模塊
          path:路徑操作模塊
          url: 解析地址的模塊
          querystring: 解析參數字符串的模塊
          基本使用:1 先引入 2 再使用
          // 引入模塊
          var fs = require('fs');
          1
          2
          第三方模塊
          第三方模塊是由 社區或個人 提供的
          比如:mime模塊/art-template/jquery…
          基本使用:1 先通過npm下載 2 再引入 3 最后使用
          用戶自定義模塊
          由開發人員創建的模塊(JS文件)
          基本使用:1 創建模塊 2 引入模塊
          注意:自定義模塊的路徑必須以./獲取../開頭
          // 加載模塊
          require('./a')     // 推薦使用,省略.js后綴!

          require('./a.js')
          1
          2
          3
          4
          模塊導入
          /* 
            nodejs中模塊分為3大類
              1. nodejs本身提供的核心模塊   fs http path url querystring
                核心模塊不需要安裝,直接導入即可。
                核心模塊的加載語法: const fs = require('fs')
              
              2. 第三方模塊  mime art-template
                第三方模塊: 必須先安裝(npm install XXX)  才能導入
                第三方模塊的加載語法: npm install XXX   const mime = require('mime')
              
              3. 自定義的模塊 一個js文件 
                不需要安裝  只需要自己創建一個js文件
                自定義模塊的加載語法:  require('模塊的路徑')  模塊不能是名字,必須是路徑  ./ ../ .js后綴是可以省略

            require加載規則(以mime模塊為例)
            1. 判斷是否是路徑, 如果是  就是自定義模塊
            2. 如果是名字 判斷是否是核心模塊
            3. 如果是第三方模塊  在當前目錄找node_modules
            4. 在node_modules中查找mime文件夾
            5. 查找是否有package.json, 查看是否main屬性
            6. 判斷是否有main, 如果沒有,默認查找index.js  index.json index.node
            7. 如果沒有
            8. 如果找不到,就去上一層目錄,一直找到根目錄
            9, 如果還沒有,就說明模塊不存在
          */

          模塊導出
          /* 
            1. 模塊中定義的變量和函數都是私有的
            2. 任意的一個模塊中, 都有自帶一個屬性 module (全局屬性) module代表的就是當前的這個模塊。
            3. module中有一個屬性  exports ,這個exports屬性是一個對象,代表的就是當前模塊的導出 module.exports當前模塊唯一能夠被外界訪問到的

          */
          //通過module.exports對外導出一些值
          module.exports = 值  只能導出一個值
          module.exports = {}  可以把所有要導出的內容都放到一個新的對象中
          module.export.xxx = 值
          /* 
            在任意的模塊中 module.exports表示該模塊的導出
            為了我們方便導出, 每個模塊中還提供了 exports  
            exports 初始狀態下,和module.exports指向了同一個對象。

            注意點: 如果通過exports的方式來導出內容,只能給對象增加屬性 不能替換這個對象
          */
          // 我們真正到處的對象是module.exports指向的對象
          exports = {} // 這樣只是改了exports的指向,而module.exports的指向沒有改變,所以這樣是不對的
          // 以下這種是允許的
          exports.xxx = '值'

          express與mysql
          首先需要安裝mysql模塊

          npm i mysql
          1
          基本使用
          // 導入第三方包
          const mysql = require('mysql')
          // 創建連接
          var connection = mysql.createConnection({
            // 本地
            host: 'localhost',
            user: 'root',
            password: 'root',
            // 數據庫名稱
            database: 'mydb',
            port: 3306
          })

          // 連接數據庫
          connection.connect()

          // 執行sql語句
          connection.query('select * from user where id = 8', (err, result) => {
            if (err) return console.log('查詢失敗', err)
            // result返回的是數組, 數組中是一個對象
            console.log(result)
          })

          // 關閉連接
          connection.end()


          查詢語句
          var name = 'zs'
          // 使用?表示占位,可以防止sql注入
          connect.query(`select * from user where name=?`, name, (err, result) => {
            if (err) return console.log('錯誤了', err)
            console.log(result)
          })
          1
          2
          3
          4
          5
          6
          插入語句
          connect.query(
            'insert into user (name, age, gender, content) values (?, ?, ?, ?)',
            ['zs', 18, '男', '哈哈哈哈'],
            err => {
              if (err) return console.log('錯誤', err)
              console.log('添加成功了')
            }
          )

          // 方式2
          connect.query(
            'insert into user set ?',
            {
              name: 'zs',
              age: 30,
              gender: '男',
              content: '哈哈哈'
            },
            (err, result) => {
              if (err) return console.log('錯誤', err)
              console.log('添加成功了', result)
            }
          )


          修改語句
          connect.query(
            'update user set ? where id = ?',
            [
              {
                name: 'zs',
                age: 30,
                gender: '男',
                content: '哈哈哈'
              },
              10
            ],
            (err, result) => {
              if (err) return console.log('錯誤', err)
              console.log('添加成功了', result)
            }
          )

          刪除語句
          connect.query('delete from user where id = ?', 10, (err, result) => {
            if (err) return console.log('失敗', err)
            console.log(result)
          })
          1
          2
          3
          4
          登錄狀態保持
          http是無狀態的,但是隨著技術的發展,我們需要記住某些東西,但是因為http是無狀態的,無法讓服務器記住東西,因此就引入了cookie和session這兩個東西,cookie用于瀏覽器端,session用于服務器端。

          以用戶登錄為例:

          當用戶登錄時,瀏覽器會給服務器發送請求,這時候服務器就會開辟一個空間用于存放session數據,并且會把生成的sessionId返回給瀏覽器,存放在瀏覽器的cookie中,之后瀏覽器在請求服務器的時候,就會去比對是否存在這個session。這樣你的登錄狀態就已經保持下來了

          cookie的特點

          cookie大小只有4k
          cookie每次請求的時候,都會自動攜帶
          cookie可以設置過期時間
          為了方便使用,我們可以使用express-session這個包,可以很方便使用session

          express-session步驟:
          1. 下載  npm i express-session
          2. 導入  const session = require("express-session")
          3. 使用session中間件
          app.use(session({
              secret: 'itcast',
              // 設置瀏覽器端cookie的名字, 默認connect.sid
              name: 'itcast',
              resave: false,
              // 在瀏覽器和服務器連接的第一時間,分配session  給瀏覽器指定一個cookie
              saveUninitialized: true
          }))
          可以通過req.session訪問到session
          4. 登錄成功,把登錄成功的用戶信息存儲到 req.session.xxx中
          5. 提供一個中間件,這個中間件在路由的前面,判斷 req.session.xxx是否有值,有值,放走,沒值,去登錄,細節: 如果是/login 直接放走
          6. 退出功能:  把req.session.xxx 清空即可


          瀏覽器登錄和退出
          1. 登錄做什么  把用戶名和密碼給服務器
          2. 退出做什么, 1. 告訴服務器,要退出   2.(清緩存也行)

          yarn和npm的說明
          官網:https://yarn.bootcss.com/

          Yarn是由Facebook、Google、Exponent 和 Tilde 聯合推出了一個新的 JS 包管理工具 ,Yarn 是為了彌補 npm 的一些缺陷而出現的。

          Yarn 緩存了每個下載過的包,所以再次使用時無需重復下載。
          同時利用并行下載以最大化資源利用率,因此安裝速度更快。
          yarn的用法和npm的用法差不多
          yarn命令
          初始化一個新項目
          yarn init
          1
          添加依賴包
          yarn add 包名
          1
          升級依賴包
          yarn upgrade 包名
          1
          移除依賴包
          yarn remove 包名
          1
          安裝項目的全部依賴
          yarn
          1
          全局安裝
          yarn global add 包名
          1
          使用gulp自動化構建
          官網:https://gulpjs.com/

          中文文檔:https://www.gulpjs.com.cn/

          用自動化構建工具增強你的工作流程!

          在開發過程中,有很多重復性的工作需要執行。

          less轉成css
          對css代碼壓縮混淆
          對js代碼壓縮混淆
          寫完代碼后需要刷新瀏覽器
          無法共用模版
          gulp是前端開發過程中對代碼進行構建的工具,是自動化項目的構建利器;她不僅能對網站資源進行優化,而且在開發過程中很多重復的任務能夠使用正確的工具自動完成;使用她,我們不僅可以很愉快的編寫代碼,而且大大提高我們的工作效率。

          gulp -----> grunt ------>webpack

          環境安裝
          初始化項目
          npm init -y
          1
          全局安裝gulp
          npm install gulp -g 
          yarn global add gulp
          1
          2
          作為項目的依賴進行安裝
          yarn add gulp --save-dev      或者    
          yarn add gulp --save-dev
          --save-dev 等同于 -D
          如果這個依賴包只是在開發階段需要用到,需要加-D
          1
          2
          3
          4
          新建gulpfile.js文件
          // 參數1: 任務名
          // 參數2: 任務需要執行的內容
          gulp.task('aa', function() {
            console.log('哈哈')
          })
          1
          2
          3
          4
          5
          執行任務
          gulp 任務名;

          gulp; 如果不接任務名,那么會執行默認的 default任務
          1
          2
          3
          glup任務-文件拷貝-lib
          文件拷貝使用到了gulp提供的幾個核心方法
          gulp.task: 定義任務

          gulp.src() 讀取文件

          gulp.pipe() 把文件交給管道處理

          gulp.dest() 輸出文件到某個目錄

          gulp.task定義任務
          gulp.src('./src/lib/**/*.*')把文件讀取成一個文件流
          gulp.pipe() 把文件流交給下一個流
          gulp.dest('./dist/lib')輸出文件
          // 簡單拷貝, 處理 lib文件夾, lib文件不需要做任何的處理,只需要拷貝到dist目錄
          // 任務需要加一個return, 表示任務完成
          gulp.task('lib', function() {
            // 讀取文件
            // gulp.src() 讀取文件
            // gulp.pipe() 管道
            // gulp.dest() 放到哪兒
            return gulp.src('./src/lib/**/*.*').pipe(gulp.dest('./dist/lib'))
          })
          1
          2
          3
          4
          5
          6
          7
          8
          9
          gulp任務-js代碼壓縮與混淆
          gulp-uglify-es: 給js代碼進行壓縮,處理ES6的代碼

          gulp-rename: 重命名

          安裝依賴
          yarn add gulp-uglify-es --save-dev 
          1
          配置任務
          const uglify = require('gulp-uglify-es').default

          gulp.task('js', function() {
            return gulp
              .src('./js/*.js')
              .pipe(uglify())
              .pipe(gulp.dest('./dist/js'))
          })
          1
          2
          3
          4
          5
          6
          7
          8
          安裝重命名依賴
          yarn add gulp-rename -D
          1
          重命名配置
          task('js', function() {
            return src('./js/*.js')
              .pipe(dest('./dist/js'))
              .pipe(uglify())
              .pipe(
                rename({
                  // 配置重命名的后綴名
                  suffix: '.min'
                })
              )
              .pipe(dest('./dist/js'))
          })
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          gulp任務-less處理
          gulp-less: 把less變成css

          gulp-rename: 重命名

          gulp-minify-css: 壓縮css代碼

          安裝依賴包
          yarn add gulp-less -D
          1
          less任務
          // less任務
          task('less', function() {
            return src('./less/*.less')
              .pipe(less())
              .pipe(
                rename({
                  extname: '.css'
                })
              )
              .pipe(dest('./dist/css'))
          })
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          安裝css壓縮處理包
          yarn add gulp-minify-css -D
          1
          壓縮css
          // less任務
          task('less', function() {
            return src('./less/*.less')
              .pipe(less())
              .pipe(
                rename({
                  extname: '.css'
                })
              )
              .pipe(dest('./dist/css'))
              .pipe(minifycss())
              .pipe(
                rename({
                  suffix: '.min'
                })
              )
              .pipe(dest('./dist/css'))
          })
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          gulp任務-圖片壓縮
          gulp-imagemin: 可以對圖片進行壓縮

          gulp-cache: 圖片壓縮比較耗時的一個任務, 如果每次都對所有的圖片進行重新壓縮,比較浪費時間, 會緩存下來所有已經壓縮過的圖片

          安裝依賴
          yarn add gulp-imagemin -D
          1
          壓縮圖片的任務
          task('image', function() {
            return src('./img/*')
              .pipe(imagemin())
              .pipe(dest('./dist/img'))
          })
          1
          2
          3
          4
          5
          安裝gulp-cachae
          yarn add  gulp-cache -D
          1
          壓縮圖片是比較耗時的,我們可以使用gulp-cache來緩存已經壓縮過的圖片
          task('image', function() {
            return src('./img/*')
              .pipe(cache(imagemin()))
              .pipe(dest('./dist/img'))
          })
          1
          2
          3
          4
          5
          參考資料:https://www.cnblogs.com/yuzhongwusan/p/5417090.html

          gulp任務-處理html
          gulp-minify-html: 壓縮html文件

          gulp-html-extend: 語句當前html去導入另一個html

          壓縮html
          yarn add gulp-minify-html -D
          1
          使用
          // 處理html
          task('html', function() {
            return src('./src/*.html')
              .pipe(minifyHtml())
              .pipe(dest('./dist'))
          })
          1
          2
          3
          4
          5
          6
          導入html
          yarn add gulp-html-extend -D
          1
          // 處理html
          task('html', function() {
            return src('./src/*.html')
              .pipe(extender())
              .pipe(minifyHtml())
              .pipe(dest('./dist'))
          })
          1
          2
          3
          4
          5
          6
          7
          在頁面中,如何導入html

          <!-- @@include ./template/header.html -->
          1
          gulp任務-清空任務
          安裝
          yarn add del -D
          1
          配置任務
          task('clean', function() {
            return del('./dist')
          })
          1
          2
          3
          gulp-任務整合series
          task('build', gulp.series('clean', 'html', 'less', 'js', 'image', 'lib'))
          1
          gulp任務-監聽文件的變化
          // 實現一個,修改代碼,會自動執行任務
          // 監聽的任務,,,,,,做一件事件,當我們修改了對應的文件,需要執行對應的任務
          // gulp.watch() 監視文件
          task('watch', function() {
            // 參數1:監視的文件
            // 參數2: 對應的任務, 多個任務
            watch('./src/**/*.html', series('html'))
            watch('./src/less/*.less', series('less'))
            watch('./src/js/*.js', series('js'))
            watch('./src/lib/**/*.*', series('lib'))
            watch('./src/img/*.*', series('img'))
          })

          gulp任務-自動刷新
          安裝
          yarn add gulp-connect -D
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

          vue路由加載頁面時,數據返回慢的問題

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          場景:

          vue路由加載頁面時,數據返回慢的時候頁面會有閃動的效果,數據加載前和加載后的區別。(特別是el-table表格數據)

          思路:

          路由前加載數據,等數據加載完再路由渲染頁面

          解決方案:

          使用vue-router的 路由守衛 beforeRouteEnter,組件內直接定義以下路由導航守衛,和鉤子函數的寫法一樣,下面列出三種路由守衛:

           beforeRouteEnter(to,from,next)0{
                  // 在渲染該組件的對應路由被 confirm 前調用// 不!能!獲取組件實例 `this`
                  // 因為當守衛執行前,組件實例還沒被創建
              } 復制代碼
           beforeRouteUpdate(to,from,next){
                  // 在當前路由改變,但是該組件被復用時調用
                  // 舉例來說,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
                  // 由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
                  // 可以訪問組件實例 `this`
              } 復制代碼
           beforeRouteLeave(to,from,next){
                  // 導航離開該組件的對應路由時調用// 可以訪問組件實例 `this`
              } 復制代碼

          vue-router詳細,具體訪問:導航守衛 數據獲取

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務。


          layui數據表格如何加工具欄?

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          實現的最終效果圖(文末會貼出全部代碼,方便參考) 



          1, 將此行代碼加在紅線所在的位置

          ,{fixed: 'right', width: 150, align:'center', toolbar: '#toolbarDemo'}


          2,在合適的HTML位置加入 

          <script type="text/html" id="toolbarDemo">
              <div class="layui-btn-container">
                  <button class="layui-btn layui-btn-sm" lay-event="update">編輯</button>
                  <button class="layui-btn layui-btn-danger layui-btn-sm" lay-event="delete">刪除</button>
              </div>
          </script>
          全部代碼:

          {include file="common/header"}

          <div class="x-nav">
                <span class="layui-breadcrumb">
                  <a href="">首頁</a>
                  <a href="">演示</a>
                  <a>
                    <cite>導航元素</cite></a>
                </span>
              <a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" href="javascript:location.replace(location.href);" title="刷新">
                  <i class="layui-icon" style="line-height:30px">?</i></a>
          </div>

          <table class="layui-hide" id="test" lay-size="sm" lay-filter="test"></table>

          <script type="text/html" id="toolbarDemo">
              <div class="layui-btn-container">
                  <button class="layui-btn layui-btn-sm" lay-event="update">編輯</button>
                  <button class="layui-btn layui-btn-danger layui-btn-sm" lay-event="delete">刪除</button>
              </div>
          </script>

          <script>
              layui.use('table', function(){
                  var table = layui.table;

                  table.render({
                      elem: '#test'
                      ,url:"{:url('admin/user/page')}"
                      ,page: { //支持傳入 laypage 組件的所有參數(某些參數除外,如:jump/elem) - 詳見文檔
                          layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定義分頁布局
                          //,curr: 5 //設定初始在第 5 頁
                          ,limit:10 //一頁顯示多少條
                          ,limits:[5,10,15]//每頁條數的選擇項
                          ,groups: 2 //只顯示 2 個連續頁碼
                          ,first: "首頁" //不顯示首頁
                          ,last: "尾頁" //不顯示尾頁
                      }
                      ,cols: [[
                          {field:'id', width:80, title: '代理ID', sort: true}
                          ,{field:'username', width:100, title: '代理名稱'}
                          ,{field:'level', width:100, title: '代理級別'}
                          ,{field:'email', width:80, title: '電子郵箱'}
                          ,{field:'phone', width:280, title: '手機號'}
                          ,{field:'agent_id', width:280, title: '上級代理ID'}
                          ,{field:'status', width:280, title: '是否啟用'}
                          ,{field:'isAuth', width:280, title: '是否已經認證'}
                          ,{field:'money', width:280, title: '金額'}
                          ,{field:'created_time', width:280, title: '訪問時間',sort: true}
                          ,{fixed: 'right', width: 150, align:'center', toolbar: '#toolbarDemo'}
                      ]]

                  });


                  //監聽工具條
                  table.on('tool(test)', function(obj){ //注:tool是工具條事件名,test是table原始容器的屬性 lay-filter="對應的值"
                      console.log(obj);
                      var data = obj.data; //獲得當前行數據
                      var layEvent = obj.event; //獲得 lay-event 對應的值(也可以是表頭的 event 參數對應的值)
                      var tr = obj.tr; //獲得當前行 tr 的DOM對象

                      if(layEvent === 'detail'){ //查看
                          //do somehing
                      } else if(layEvent === 'del'){ //刪除
                          layer.confirm('真的刪除行么', function(index){
                              obj.del(); //刪除對應行(tr)的DOM結構,并更新緩存
                              layer.close(index);
                              //向服務端發送刪除指令
                          });
                      } else if(layEvent === 'edit'){ //編輯
                          //do something

                          //同步更新緩存對應的值
                          obj.update({
                              username: '123'
                              ,title: 'xxx'
                          });
                      }
                  });

              });

          </script>
          </body>
          </html>

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

          Echarts 動態更新散點圖

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

           最近遇到一個作業,要求使用 Echarts 散點圖,本來這個圖是很容易的,官網上也有很多的教程。但是如果可以動態的更新 Echarts 散點圖就更好了。我本身對 js 不感興趣,經過不停的查找資料最終實現了這一功能。
          我的項目是 Servlet + jsp + Echarts。先從 Servlet 入手,我們的項目需要傳遞的數值是 x 坐標和 y 坐標。我首先寫了一個 JavaBean

          julie.java

          package JavaBean;

          public class julei {
              public julei(double x, double y) {
                  this.x = x;
                  this.y = y;
              }
              double x;

              public double getX() {
                  return x;
              }

              public void setX(double x) {
                  this.x = x;
              }

              public double getY() {
                  return y;
              }

              public void setY(double y) {
                  this.y = y;
              }

              double y;

              @Override
              public String toString() {
                  return "[" + this.x + "," + this.y + "]";
              }
          }


          Servlet中的代碼,因為使用的是 json 來傳遞的數據,所以 json 相關的包還是少不了的。
          BackServlet

          package Servlet;

          import JavaBean.Readtxt;
          import JavaBean.julei;
          import org.json.JSONArray;
          import org.json.JSONObject;

          import java.io.IOException;
          import java.io.PrintWriter;
          import java.util.ArrayList;
          import java.util.HashMap;
          import java.util.List;
          import java.util.Map;

          @javax.servlet.annotation.WebServlet("/BackServlet")
          public class BackServlet extends javax.servlet.http.HttpServlet {
              protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {



                  List<julei> list = new ArrayList<>();
                  try {
                      list = Readtxt.out();//這是我們項目中的一個類,不重要。
                  }catch (Exception e)
                  {
                      System.out.println(e.toString());
                  }


                  JSONArray jsonArray = new JSONArray(list);
                  System.out.println(jsonArray.toString());
                  //最重要的就是這一句,將數據發送給誰來申請的位置
                  response.getWriter().write(jsonArray.toString());


              }

              protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

              }
          }


          好了,現在到了最重要的前端方面了。
          index.jsp
          正常聲明散點圖,只要把data聲明為空就好。

            var myChart = echarts.init(document.getElementById('man'));
                    var option = {
                      title : {
                        text: '死亡分布圖',
                      },
                      xAxis: {axisTick: {//決定是否顯示坐標刻度
                          alignWithLabel: true,
                          show:true
                        },},
                      yAxis: {},
                      series: [{
                        symbolSize: 20,
                        data: [],
                        type: 'scatter'
                      }]
                    };
                    myChart.setOption(option);

          數據接收部分:

          var num = [];
                    var gao = new Array();
                    $.ajax({
                      type : "post",
                      async : true, //異步請求(同步請求將會鎖住瀏覽器,其他操作須等請求完成才可執行)
                      url : "BackServlet", //請求發送到TestServlet
                      data : {},
                      dataType : "json", //返回數據形式為json

                      //7.請求成功后接收數據name+num兩組數據
                      success : function(result) {
                        //result為服務器返回的json對象
                        if (result) {
                          //8.取出數據存入數組

                          for (var i = 0; i < result.length; i++) {

                            gao.push([result[i].x,result[i].y]);//這一句很重要,它將數據轉化為了正確的格式。

                          }

                          myChart.hideLoading(); //隱藏加載動畫

                          //9.覆蓋操作-根據數據加載數據圖表
                          myChart.setOption({
                            series : [ {
                              // 根據名字對應到相應的數據
                              data : gao//在這里對data進行賦值。
                            } ]
                          });

                        }

                      },
                      error : function(errorMsg) {
                        //請求失敗時執行該函數
                        alert("圖表請求數據失敗!");
                        myChart.hideLoading();
                      }
                    })




          完畢

          我把整個jsp都放上來了,但是里面的 css 還有 js 就不放了,重點是傳數據的那一部分。

          <%@ page language="java" contentType="text/html; charset=UTF-8"
                   pageEncoding="UTF-8"%>
          <!DOCTYPE html>
          <html lang="zh-CN">
          <head>
            <meta charset="UTF-8">
            <title>LOL數據分析</title>
            <script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
            <script type="text/javascript" src='js/echarts.js'></script>
            <link rel="stylesheet" href="css/jquery.fullPage.css">
            <link rel="stylesheet" href="css/style.css">
            <link rel="icon" >
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <script src="https://code.highcharts.com.cn/highcharts/highcharts.js"></script>
            <script src="https://code.highcharts.com.cn/highcharts/modules/exporting.js"></script>
            <script src="https://img.hcharts.cn/highcharts-plugins/highcharts-zh_CN.js"></script>
          </head>

          <body>
          <div class="bgcolor">
            <div style="z-index:100;" id="dowebok">
              <!--第一屏-->

              <div class="section">
                <div class="ly-box01">
                  <img class="ly-img01" src="img/logol.png" style="width:100%;height:100%">

                </div>
              </div>

           

              <!--第三屏-->

              <div class="section">
                <div class="timeline"></div>
                <div class="timepoint21"></div>
                <div class="ly-box11">
                  <div id="man" style=" width: 600px;height: 500px;"></div>

                  <script type="text/javascript">
                    // 基于準備好的dom,初始化echarts實例
                    var value=[];
                    $.ajaxSettings.async=false;
                    var myChart = echarts.init(document.getElementById('man'));
                    var option = {
                      title : {
                        text: '死亡分布圖',
                      },
                      xAxis: {axisTick: {//決定是否顯示坐標刻度
                          alignWithLabel: true,
                          show:true
                        },},
                      yAxis: {},
                      series: [{
                        symbolSize: 20,
                        data: [],
                        type: 'scatter'
                      }]
                    };
                    myChart.setOption(option);






                    var num = [];
                    var gao = new Array(4);
                    $.ajax({
                      type : "post",
                      async : true, //異步請求(同步請求將會鎖住瀏覽器,其他操作須等請求完成才可執行)
                      url : "BackServlet", //請求發送到TestServlet
                      data : {},
                      dataType : "json", //返回數據形式為json

                      //7.請求成功后接收數據name+num兩組數據
                      success : function(result) {
                        //result為服務器返回的json對象
                        if (result) {
                          //8.取出數據存入數組

                          for (var i = 0; i < result.length; i++) {
                            gao.push([result[i].x,result[i].y]);
                          }

                      //  document.write(gao);
                          myChart.hideLoading(); //隱藏加載動畫

                          //9.覆蓋操作-根據數據加載數據圖表
                          myChart.setOption({
                            series : [ {
                              // 根據名字對應到相應的數據
                              data : gao
                            } ]
                          });

                        }

                      },
                      error : function(errorMsg) {
                        //請求失敗時執行該函數
                        alert("圖表請求數據失敗!");
                        myChart.hideLoading();
                      }
                    })






                  </script>
                </div>
                <div class="ly-triangle21"></div>
              </div>
            <!--試驗-->

            <ul class="bg-bubbles">
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
              <li><img src="img/logol.png" style="width:100%;height:100%"></li>
            </ul>

          </div>

          <audio src="music/1.mp3" autoplay="autoplay" loop="loop" />
          <script src="js/jquery-1.8.3.min.js"></script>
          <script src="js/jquery.fullPage.min.js"></script>
          <script src="js/diy.js"></script>
          </body>
          </html>
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務。

          淺入 React 生命周期相關(二)更新生命周期

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里


          更新階段分為兩部分 父組件執行 render 或者調用 this.setState。

          componentWillReceiveProps
          大部分網上教程為外部 props 發生改變才觸發 componentWillReceiveProps,其實不是,當父組件進入 render 時,無論子組件的 props 發沒發生改變,都會執行該生命周期函數。 
          函數參數有一個,為 nextProps,為將要新的 props。 
          值得注意的是,在整個更新階段的生命周期函數,只有在此函數內可以調用 this.setState 方法,當然其他也可以調用,但是會造成死循環 。

          shouldComponentUpdate
          該函數需要返回值,如沒定義則默認返回 true。當返回值為 true 時,進入 componentWillIpdate ,如為 false ,則什么都不發生。所以說這是一個可以進行 React 性能優化的地方。函數參數有兩個 nextProps 和 nextState。我們需用做的就是在 this.props、this.state、nextState、nextProps之間進行對比,來解決重復渲染的目的。

          componentWillUpdate
          如果 shouldComponentUpdate 返回值為 true 的話,生命周期會進入該函數中。在這個函數中我們可以根據實際情況做一些事情,但是不能調用 this.setState。

          render
          在更新階段的 render 來講一講 調和 過程。 render 返回的 JSX 標簽會保存在內存中,react 會通過 diff 算法來計算出最小化改動完成差異的更新。diff 是逐層遞歸比較,首先比較類型是否一樣。如果發現 <div>和 <span> 的差別的話,react 會選擇直接放棄之前的 dom 元素, 重新渲染。所以說即使是更新階段的調和過程,也會觸發組件的掛載、卸載階段。

          componentDidUpdate
          在這個時候已經更新完 dom 結構,可以重新使用 dom 操作。

          總結
          總體來說更新的生命周期要做的最重要的事情就是性能優化,減少重復渲染次數。 
          在這個方面已經有很多成熟的解決方法了,在我的博客中也會介紹如何定制更新階段的生命周期函數。 
          在使用上,最最重要的一點就是不要在除了 componentWillReceiveProps 之外的其他更新階段生命周期函數內調用 this.setState。

          相關鏈接:

          淺入 React 生命周期相關(一)掛載生命周期
          --------------------- 

          重新學習 React (一) 生命周期,Fiber 調度和更新機制

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          前幾天面試問道 react 的相關知識,對我打擊比較大,感覺對 react 認識非常膚淺,所以在這里重新梳理一下,想想之前沒有仔細思考過的東西。

          另外有說的不對的地方還請幫我指正一下,先謝謝各位啦。

          目錄索引:

          什么是生命周期和調度?

          React 有一套合理的運行機制去控制程序在指定的時刻該做什么事,當一個生命周期鉤子被觸發后,緊接著會有下一個鉤子,直到整個生命周期結束。

          生命周期

          生命周期代表著每個執行階段,比如組件初始化,更新完成,馬上要卸載等等,React 會在指定的時機執行相關的生命周期鉤子,使我們可以有機在程序運行中會插入自己的邏輯。

          調度

          我們寫代碼的時候往往會有很多組件以及他們的子組件,各自調用不同的生命周期,這時就要解決誰先誰后的問題,在 react v16 之前是采用了遞歸調用的方式一個一個執行,而在現在 v16 的版本中則采用了與之完全不同的處理(調度)方式,名叫 Fiber,這個東西 facebook 做了有兩年時間,實現非常復雜。

          具體 Fiber 它是一個什么東西呢?不要著急,我們先從最基本的生命周期鉤子看起。

          React 生命周期詳解

          首先看一下 React V16.4 后的生命周期概況(圖片來源

           

           

          • 從橫向看,react 分為三個階段:
            • 創建時
              • constructor() - 類構造器初始化
              • static getDerivedStateFromProps() - 組件初始化時主動觸發
              • render() - 遞歸生成虛擬 DOM
              • componentDidMount() - 完成首次 DOM 渲染
            • 更新時
              • static getDerivedStateFromProps() - 每次 render() 之前執行
              • shouldComponentUpdate() - 校驗是否需要執行更新操作
              • render() - 遞歸生成虛擬 DOM
              • getSnapshotBeforeUpdate() - 在渲染真實 DOM 之前
              • componentDidUpdate() - 完成 DOM 渲染
            • 卸載時
              • componentWillUnmount() - 組件銷毀之前被直接調用

          一些干貨

          • 有三種方式可以觸發 React 更新,props 發生改變,調用 setState() 和調用 forceUpdate()
          • static getDerivedStateFromProps() 這個鉤子會在每個更新操作之前(即使props沒有改變)執行一次,使用時應該保持謹慎。
          • componentDidMount() 和 componentDidUpdate() 執行的時機是差不多的,都在 render 之后,只不過前者只在首次渲染后執行,后者首次渲染不會執行
          • getSnapshotBeforeUpdate() 執行時可以獲得只讀的新 DOM 樹,此函數的返回值為 componentDidUpdate(prevProps, prevState, snapshot) 的第三個參數

          嘗試理解 Fiber

          關于 Fiber,強烈建議聽一下知乎上程墨Morgan的 live 《深入理解React v16 新功能》,這里潛水員的例子和圖片也是引用于此 live。

          背景

          我們知道 React 是通過遞歸的方式來渲染組件的,在 V16 版本之前的版本里,當一個狀態發生變更時,react 會從當前組件開始,依次遞歸調用所有的子組件生命周期鉤子,而且這個過程是同步執行的且無法中斷的,一旦有很深很深的組件嵌套,就會造成嚴重的頁面卡頓,影響用戶體驗。

          React 在V16版本之前的版本里引入了 Fiber 這樣一個東西,它的英文涵義為纖維,在計算機領域它排在在進程和線程的后面,雖然 React 的 Fiber 和計算機調度里的概念不一樣,但是可以方便對比理解,我們大概可以想象到 Fiber 可能是一個比線程還短的時間片段。

          Fiber 到底做了什么事

          Fiber 把當前需要執行的任務分成一個個微任務,安排優先級,然后依次處理,每過一段時間(非常短,毫秒級)就會暫停當前的任務,查看有沒有優先級較高的任務,然后暫停(也可能會完全放棄)掉之前的執行結果,跳出到下一個微任務。同時 Fiber 還做了一些優化,可以保持住之前運行的結果以到達復用目的。

          舉個潛水員的例子

          我們可以把調度當成一個潛水員在海底尋寶,v16 之前是通過組件遞歸的方式進行尋寶,從父組件開始一層一層深入到最里面的子組件,也就是如下圖所示。

           

           

           

          而替換成了 Fiber 后,海底變成的狹縫(簡單理解為遞歸變成了遍歷),潛水員會每隔一小段時間浮出水面,看看有沒有其他尋寶任務。注意此時沒有尋到寶藏的話,那么之前潛水的時間就浪費了。就這樣潛水員會一直下潛和冒泡,具體如下圖所示。

           

           

           

          引入 Fiber 后帶來的三個階段

          從生命周期那張圖片縱向來看,Fiber 將整個生命周期分成了三個階段:

          • render 階段
            • 由于 Fiber 會時不時跳出任務,然后重新執行,會導致該階段的生命周期調用多次的現象,所以 React V16 之前 componentWillMount(),componentWillUpdate()componentWillReceiveProps() 的三個生命周期鉤子被加上了 UNSAFE 標記
            • 這個階段效率不一定會比之前同步遞歸來的快,因為會有任務跳出重做的性能損耗,但是從宏觀上看,它不斷執行了最高優先級(影響用戶使用體驗)的任務,所以用戶使用起來會比以前更加的流暢
            • 這個階段的生命周期鉤子可能會重復調用,建議只寫無副作用的代碼
          • pre-commit 階段
            • 該階段 DOM 已經形成,但還是只讀狀態
            • 這個階段組件狀態不會再改變
          • commit 階段
            • 此時的 DOM 可以進行操作
            • 這個階段組件已經完成更新,可以寫一些有副作用的代碼和添加其它更新操作。

          簡而言之:以 render() 為界,之前執行的生命周期都有可能會打斷并多次調用,之后的生命周期是不可被打斷的且只會調用一次。所以盡量把副作用的代碼放在只會執行一次的 commit 階段。

          其它生命周期鉤子

          除了上面常用的鉤子,React 還提供了如下鉤子:

          • static getDerivedStateFromError() 在 render 階段執行,通過返回 state 更新組件狀態
          • componentDidCatch() 在 commit 階段執行,可以放一些有副作用的代碼

          更新機制

          理解了生命周期和三個執行階段,就可以比較容易理解組件狀態的更新機制了。

          setState()

          這個方法可以讓我們更新組件的 state 狀態。第一個參數可以是對象,也可以是 updater 函數,如果是函數,則會接受當前的 state 和 props 作為參數。第二個參數為函數,是在 commit 階段后執行,準確的說是在 componentDidUpdate() 后執行。

          setState() 的更新過程是異步的(除非綁定在 DOM 事件中或寫在 setTimeout 里),而且會在最后合并所有的更新,如下:

          Object.assign( previousState,
            {quantity: state.quantity + 1},
            {quantity: state.quantity + 1},
            ...
          )
          復制代碼

          之所以設計成這樣,是為了避免在一次生命周期中出現多次的重渲染,影響頁面性能。

          forceUpdate()

          如果我們想強制刷新一個組件,可以直接調用該方法,調用時會直接執行 render() 這個函數而跳過 shouldComponentUpdate()

          舉個極端例子

          function wait() { return new Promise(resolve => {
              setTimeout(() => {
                resolve(); console.log("wait");
              }, 0);
            });
          } //......省略組件創建 async componentDidMount() { await wait(); this.setState({ name: "new name" }); console.log("componentDidMount");
          }
          
          componentDidUpdate() { console.log("componentDidUpdate");
          }
          
          render() { console.log(this.state); return null } //......省略組件創建 // 輸出結果如下 // wait // {name: "new name"} // componentDidUpdate // componentDidMount // 注意 componentDidUpdate 的輸出位置,一般情況下 // componentDidUpdate 都是在componentDidMount 后面 // 執行的,但是這里因為setState 寫在了 await 后面 // 所以情況相反。 復制代碼

          結語

          了解 react 生命周期和更新機制確實有利于編寫代碼,特別是當代碼量越來越大時,錯用的 setState 或生命周期鉤子都可能埋下越來越多的雷,直到有一天無法維護。。。

          我的個人建議如下:

          • 把副作用代碼通通放在 commit 階段,因為這個階段不會影響頁面渲染性能
          • 盡可能不要使用 forceUpdate() 方法,借用 Evan You 的一句話,如果你發現你自己需要在 Vue 中做一次強制更新,99.9% 的情況,是你在某個地方做錯了事
          • 只要調用了 setState() 就會進行 render(),無論 state 是否改變
          • 知道 setState() 更新的什么時候是同步的,什么時候是異步的,參見上文
          • 不要把 getDerivedStateFromProps() 當成是 UNSAFE_componentWillReceiveProps() 的替代品,因為 getDerivedStateFromProps() 會在每次 render() 之前執行,即使 props 沒有改變




          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務。

          日歷

          鏈接

          個人資料

          藍藍設計的小編 http://www.syprn.cn

          存檔

          亚洲va欧美va天堂v国产综合