zoukankan      html  css  js  c++  java
  • 微信小程序

    mixins 概念 可百度  参考 http://ask.seowhy.com/article/21007

    大意和Python中的多重继承, java中的接口类似(java接口只是定义,实现需要子类自己写).

    而JS中没有接口的概念, 利用对象的key遍历,并合并到子类(或者叫对象)中.

    伪代码:

    var  mixin = { //混入对象包含一个方法
         demoFunction(){
    
        }  
      
    }    ;
    
    var PageOption = {  //需要继承mixin的对象
    
    };
    //内部处理mixin的逻辑
    processMixins(PageOption , mixin);
    
    //最终得到的 PageOption
    PageOption = {
        demoFunction(){
    
        }  
    };    

    mixins 可以有多个,遭遇名称冲突时的规则 见下图:    vue的component可以简单理解为 微信小程序的PageOption

    我们的框架中,mixins的处理,集中在  utils/BasePageOptionClass 中.并且暂时内置了2个 顶层mixin对象 

    //全局mixins 基础库
    var basePage = require("../mixins/BasePage.js");
    //全局 mixins 扩展库,预留
    var basePageExt = require("../mixins/BasePageExt.js");
     
    处理方法:
     
    /**
     *  处理mixins
     */
    function _processMixins__(actualOption){
     
      var app = getApp();
      var pageOption = actualOption.PageOption;
      var mixins =  pageOption.mixins||[];
      
      mixins.unshift(basePage, basePageExt);
    
      var data={};
      var methods = {};
      var lifecycleMethods = {
        "onLoad": [], "onReady": [], "onShow": [], "onHide": [], "onUnload": [],
        "onPullDownRefresh": [], "onReachBottom": [], "onShareAppMessage": [], "onPageScroll": []
      };
      for (var i=0;i< mixins.length;i++){
        var mixin = mixins[i];
          var d = mixin.data;
          if(d){
            app.util.extend(data,d);
          }
          var keys=Object.keys(mixin);
          for(key of keys){
               if(key=="data")continue;
              if (lifecycleMethods[key] ){ //生命周期函数
                if (typeof mixin[key] =="function"){ //是函数
                  lifecycleMethods[key].push(mixin[key]); //先加入的mixin生命周期函数先执行
                } else {//不是函数, 不在规范内, 作为属性,如果Page定义,舍弃,没有则并入
                  if (!actualOption[key]){ //防止mixin破坏页面定义
                    actualOption[key]=mixin[key];
                  }
                }
              }else{ //普通函数
                 actualOption[key] = mixin[key];
              }
          }
         
      }
      //合并到Page定义的data
      actualOption.PageOption.data = app.util.extend(data, actualOption.PageOption.data);
      actualOption.PageOption.__lifecycleMethods = lifecycleMethods;
    }

    这样大致实现了 vue定义的冲突解决方案.

    执行方法代码逻辑

                // mixins 生命周期函数 执行方案,总是先执行
                var __lifecycleMethods = actualOption.PageOption.__lifecycleMethods || {};
                var __lifecycleMethod = __lifecycleMethods[key];
                var mixinsRunsReturn = false;
                if (__lifecycleMethod && __lifecycleMethod.length>0){
                  for (let ii = 0; ii < __lifecycleMethod.length;ii++){
                    try{
                       var ret = __lifecycleMethod[ii].apply($target, arguments);
                       if(ret===false){ //这里预留增加了 mixin方法的返回值,如果是false,那么逻辑终止
                         mixinsRunsReturn = true;
                         break;
                       }
                    }catch(err){
                      console.log("执行mixin函数报错",err);
                      throw err;
                    }
                  }
                }
                if (mixinsRunsReturn){
                  console.log("mixin函数返回false,执行被终止");
                  return;
                }
    经过改造,原先一些定义在BasePageOptionClass中的一些方法,转移到了 /mixins/BasePage.js 中.详见代码.
     
    拓展思考:
    哪些逻辑方法适合写入mixin
     
    目前实现的:
    左划删除
    顶部可滑动菜单
     
    实现思路其实和 微信的template,component类似
    因为mixin的特性,所有引入mixin类,就引入了支持 这些操作或者效果的代码.
    wxml 直接在页面中书写, css 引入, 这个步骤 和组件的步骤是一致的.
    优点是灵活.编码规则上,多增加点前缀,避免名称冲突
    在良好的文档支持下,内部开发应该不成问题
     
     
    /**
     * 左划需要的事件
     * wxss中 增加 @import "/style/modules/left_touch.wxss";
     * 
     * 用法 Page页面增加
     * let left_touch = require("../../../mixins/left_touch.js");
     * PageOption 增加 mixins:[left_touch]
     * 
     * wxml 示例
        <view class='left_touch_block'>
          <view class="items">
            <view wx:for="{{list}}"  wx:key="{{index}}"  class="touch_block_item">
              <view data-data_path="list[{{index}}]._txtStyle"  bindtouchstart="_touchS" bindtouchmove="_touchM" bindtouchend="_touchE" data-index="{{index}}" style="{{item._txtStyle}}" class="inner touch_block_content">
                <view>{{index}}</view>
                <view>{{item.txt}}</view>
              </view>
              <view data-index="{{index}}" bindtap = "_btn_touched" class="inner touch_block_btn">删除</view>
            </view>
        </view>
      </view>
    
    其中  data-data_path 标志 数据的层级,用户 设置单项的_txtStyle 属性,此属性为插件内部使用,外部数据不需要初始化这个属性
    _btn_touched 方法需要自己写,见下方代码示例部分,根据具体逻辑编写
    
    本插件更多的是为了基本的排版和通用事件的编写
    
     * 
     */
    var obj = {
    
      data:{
        _delBtnWidth: 180   //删除按钮宽度单位(rpx)  
      },
      onLoad: function (options) {
        // 页面初始化 options为页面跳转所带来的参数  
        this._initEleWidth();
      },  
      /**
       * 触摸开始事件,记录 开始坐标
       */
      _touchS: function (e) {
        if (e.touches.length == 1) {
          this.setData({
            //设置触摸起始点水平方向位置  
            _startX: e.touches[0].clientX
          });
        }
      },
      /**
       * 触摸移动中事件
       * 构建简单动画, 即 删除按钮 动态展现
       */
      _touchM: function (e) {
        var that = this
        
        if (e.touches.length == 1) {
          //手指移动时水平方向位置  
          var moveX = e.touches[0].clientX;
          //手指起始点位置与移动期间的差值  
          var disX = this.data._startX - moveX;
          var _delBtnWidth = this.data._delBtnWidth;
          var txtStyle = "";
          if (disX == 0 || disX < 0) {//如果移动距离小于等于0,文本层位置不变  
            txtStyle = "left:0px";
          } else if (disX > 0) {//移动距离大于0,文本层left值等于手指移动距离  
            txtStyle = "left:-" + disX + "px";
            if (disX >= _delBtnWidth) {
              //控制手指移动距离最大值为删除按钮的宽度  
              txtStyle = "left:-" + _delBtnWidth + "px";
            }
          }
          //获取手指触摸的是哪一项  
          var dataset = e.currentTarget.dataset;
          var index = dataset.index;
        
          var data_path = dataset.data_path
          var updateObject = {};
          updateObject[data_path] = txtStyle;
          this.setData(updateObject);
        }
      },
    /**
     * 触摸结束事件
     * 结合触摸开始时的坐标,算出移动的距离
     * 如果距离超出删除按钮的一半,那么 算是移动成功,展示全部删除按钮,否则 删除按钮隐藏
     * 注意 更新数据方式,并不是网上示例的全部数据更新
     */
      _touchE: function (e) {
        var self= this;
        if (e.changedTouches.length == 1) {
          //手指移动结束后水平位置  
          var endX = e.changedTouches[0].clientX;
          //触摸开始与结束,手指移动的距离  
          var disX = this.data._startX - endX;
          var _delBtnWidth = this.data._delBtnWidth;
          var index = e.currentTarget.dataset.index;
    
          var data_path = e.currentTarget.dataset.data_path;
          var updateObject = {};
          //如果距离小于删除按钮的1/2,不显示删除按钮  
          var txtStyle = "left:0px";
          if( disX > _delBtnWidth / 2 ){
            txtStyle = "left:-" + _delBtnWidth + "px" 
            if (self._lastMovedElePath) {
              updateObject[self._lastMovedElePath] = "left:0px";
            }
            self._lastMovedElePath = data_path
          } else{
           
          }
          //获取手指触摸的是哪一项  
          
          updateObject[data_path] = txtStyle;
         
          //更新列表的状态  
          this.setData(updateObject);
        }
      },
      //获取元素自适应后的实际宽度  
      _getEleWidth: function (w) {
        var real = 0;
        try {
          var res = wx.getSystemInfoSync().windowWidth;
          var scale = (750 / 2) / (w / 2);//以宽度750px设计稿做宽度的自适应  
          // console.log(scale);  
          real = Math.floor(res / scale);
          return real;
        } catch (e) {
          return false;
          // Do something when catch error  
        }
      },
      _initEleWidth: function () {
        var _delBtnWidth = this._getEleWidth(this.data._delBtnWidth);
        this.setData({
          _delBtnWidth: _delBtnWidth
        });
      },
      /**
       * 点击删除按钮事件  
       * 这是个示例方法,请在具体的页面Page中重写此方法逻辑
       */ 
      _btn_touched: function (e) {
        var that = this
        wx.showModal({
          title: '提示',
          content: '是否删除?',
          success: function (res) {
            if (res.confirm) {
              //获取列表中要删除项的下标  
              var index = e.target.dataset.index;
              
              // var list = that.data.list;
              // //移除列表中下标为index的项  
              // list.splice(index, 1);
              // //更新列表的状态  
              // that.setData({
              //   list: list
              // });
            } else {
              //做页面重新渲染,或什么都不做
            }
          }
        })
    
      }
    
    
    
    
    };
    module.exports= obj;
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    KafkaZookeeper1-整体介绍
    spark thrift server configuration
    Spark Streaming 总结
    SparkSession
    Spark SQL
    Kafka Consumer2
    Kafka Consumer1
    Storm Spout
    java Future && Guava Future
    基本命令
  • 原文地址:https://www.cnblogs.com/jifsu/p/7856347.html
Copyright © 2011-2022 走看看