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;
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Windows 科研软件推荐
    有关Python 包 (package) 的基本知识
    《Using Python to Access Web Data》Week4 Programs that Surf the Web 课堂笔记
    Coursera助学金申请模板
    《Using Databases with Python》 Week2 Basic Structured Query Language 课堂笔记
    Jupyter 解决单个变量输出问题
    解决 pandas 中打印 DataFrame 行列显示不全的问题
    《Using Python to Access Web Data》 Week3 Networks and Sockets 课堂笔记
    缓存击穿及解决方案
    jvm垃圾收集器
  • 原文地址:https://www.cnblogs.com/jifsu/p/7856347.html
Copyright © 2011-2022 走看看