weex开发的笔记

启动npm服务 npm run serve:lazy相当于本地发布服务,连接本地服务可实时查看weex页面的更新

 

向weex端注册方法和组件

/// 功能组件
[WXSDKEngine registerModule:@"MallModule" withClass:NSClassFromString(@"BHEMallWxEventModule")];
/// UI组件
[WXSDKEngine registerComponent:@"input" withClass:NSClassFromString(@"BHEWeexEditText")];

设置下载等自定义代理和注入JS函数

/// 实现自定义代理
[WXSDKEngine registerHandler:loader withProtocol:@protocol(WXImgLoaderProtocol)];
[WXSDKEngine registerHandler:loader withProtocol:@protocol(WXURLRewriteProtocol)];

/// 注入JS服务函数
/**
 * @abstract Registers a component for a given name, options and js code
 *
 * @param name The service name to register
 *
 * @param options The service options to register
 *
 * @param serviceScript service js code to invoke
 *
 */
+ (void)registerService:(NSString *)name withScript:(NSString *)serviceScript withOptions:(NSDictionary * _Nullable)options;

Module提供方法给到weex端使用

/// weex端调用时方法名为最前面部分addEventListener(xx,(ret)=>{code;}),其他按照参数个数依次补充即可,不需要补充方法名
WX_EXPORT_METHOD(@selector(addEventListener:callback:))

weex端写一个js功能模块

/// date_utils.js
const ONE_SECOND = 1000;
const ONE_MINUTE = 60 * ONE_SECOND;
const ONE_HOUR = 60 * ONE_MINUTE;
const ONE_DAY = 24 * ONE_HOUR;

export default {
  one_day: ONE_DAY,
  one_hour: ONE_HOUR,
  one_minute: ONE_MINUTE,
  one_second: ONE_SECOND,
  getSystemCurrTime() {//只到秒
    var timestamp = Date.parse(new Date());
    //var timestamp = (new Date()).valueOf();
    //var timestamp=new Date().getTime();
    return parseInt(timestamp / 1000);
  },
  getSystemCurrTime2() {//精度:毫秒
    var timestamp = Date.parse(new Date());
    //var timestamp = (new Date()).valueOf();
    //var timestamp=new Date().getTime();
    return parseInt(timestamp);
  },
  getCurrServerTime(serverTime) {
    if (!serverTime) {
      serverTime = 0;
    }
    return serverTime + this.getSystemCurrTime();
  },
  getTimeStrMDH(seconds) {
    var dateTime = new Date(seconds * 1000);
    var month = dateTime.getMonth() + 1;
    var day = dateTime.getDate();
    var hour = dateTime.getHours();
    return month + "月" + day + "日" + hour + "时";
  },
  calculateCutTime(timeInterval) {  //传进来的是毫秒的时间戳
    var day = parseInt(timeInterval / ONE_DAY);
    timeInterval %= ONE_DAY;
    var hour = parseInt(timeInterval / ONE_HOUR);
    timeInterval %= ONE_HOUR;
    var minute = parseInt(timeInterval / ONE_MINUTE);
    timeInterval %= ONE_MINUTE;
    var second = parseInt(timeInterval / ONE_SECOND);
    if (day <= 9) day = '0' + day;
    if (hour <= 9) hour = '0' + hour;
    if (minute <= 9) minute = '0' + minute;
    if (second <= 9) second = '0' + second;

    return [day, hour, minute, second];
  },
  getCountTime(time) {
    var countTime = '';
    var day = parseInt(time / ONE_DAY);
    time %= ONE_DAY;
    var hour = parseInt(time / ONE_HOUR);
    time %= ONE_HOUR;
    var minute = parseInt(time / ONE_MINUTE);
    time %= ONE_MINUTE;
    var second = parseInt(time / ONE_SECOND);
    if (day <= 9) day = '0' + day;
    if (hour <= 9) hour = '0' + hour;
    if (minute <= 9) minute = '0' + minute;
    if (second <= 9) second = '0' + second;
    countTime = day + '天' + hour + '时' + minute + '分' + second + '秒';
    return countTime;
  },
  getCountTime3(time) {
    var countTime = '';
    var day = parseInt(time / ONE_DAY);
    time %= ONE_DAY;
    var hour = parseInt(time / ONE_HOUR);
    time %= ONE_HOUR;
    var minute = parseInt(time / ONE_MINUTE);
    time %= ONE_MINUTE;
    var second = parseInt(time / ONE_SECOND);
    if (hour <= 9) hour = '0' + hour;
    if (minute <= 9) minute = '0' + minute;
    if (second <= 9) second = '0' + second;
    if (day > 0) {
      countTime = day + '天' + hour + '小时' + minute + '分';
    } else {
      countTime = hour + '小时' + minute + '分' + second + '秒';
    }
    return countTime;
  },
  getCountTime2(time) {
    var countTime = '';
    var day = parseInt(time / ONE_DAY);
    time %= ONE_DAY;
    var hour = parseInt(time / ONE_HOUR);
    time %= ONE_HOUR;
    var minute = parseInt(time / ONE_MINUTE);
    time %= ONE_MINUTE;
    var second = parseInt(time / ONE_SECOND);
    if (day > 0) {
      countTime += day + '天';
      countTime += hour + '小时';
      countTime += minute + '分';
      countTime += second + '秒';
    } else {
      if (hour > 0) {
        countTime += hour + '小时';
        countTime += minute + '分';
        countTime += second + '秒';
      } else {
        if (minute > 0) {
          countTime += minute + '分';
          countTime += second + '秒';
        } else {
          if (second > 0) {
            countTime += second + '秒';
          }
        }
      }
    }
    return countTime;
  },
  dateFormat(dateTime, fmt) {
    if (!dateTime) {
      return dateTime
    }
    if (typeof dateTime == 'string' && !isNaN(dateTime)) {
      dateTime = +dateTime
    }
    dateTime = new Date(dateTime);
    var o = {
      "M+": dateTime.getMonth() + 1, //月份
      "d+": dateTime.getDate(), //
      "h+": dateTime.getHours(), //小时
      "m+": dateTime.getMinutes(), //
      "s+": dateTime.getSeconds(), //
      "q+": Math.floor((dateTime.getMonth() + 3) / 3), //季度
      "S": dateTime.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (dateTime.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
      if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
  }
}

使用定义的js功能模块时(相当于创建对象实例)

import dateUtil from './utils/date_utils.js';

引用其他vue文件的UI组件

  import navigationBar from "./navigator.vue";
  import noNetworking from './no_networking.vue';
  import pro_tag from '../items/pro_tag.vue';

/// 通过模块名字实例化原生模块对象用作调用原生模块方法
  const dom = weex.requireModule('dom');
  const myModule = weex.requireModule('MallModule');
  const navigator = weex.requireModule('navigator');

  export default {
    components: { navigationBar, noNetworking, pro_tag },
 }

 weex调用原生方法

getUserInfo(callback) {
    var msg = {
      "operation": "getUserInfo"
    };
    // myModule.log('请求获取用户信息');
    bridgeModule.commandInterface(JSON.stringify(msg), function (e) {
      var json = JSON.parse(e);
      // myModule.log('用户信息:' + e);
      if (callback) {
        callback(json);
      }
    }, function (failed) {
      // myModule.log('获取登用户息失败:' + failed);
      if (callback) {
        callback({});
      }
    })
  },


WX_EXPORT_METHOD(@selector(commandInterface:finalCallBack:finalCallbackFail:))
-(void)commandInterface:(NSString *)param finalCallBack:(WXModuleKeepAliveCallback)callback finalCallbackFail:(WXModuleKeepAliveCallback)failCallback

 weex给控件赋值样式的几个方式

/// 样式应该为class加上style
/// 直接在标签内作为属性编写
<text v-else-if="item.nOriginalPrice>item.nSalePrice" style="font-family: PingFang-SC-Medium;font-size: 24px;color: #C7C7CC;text-align: left;text-decoration: line-through;">¥{{item.nOriginalPrice/100.0}}</text>

/// 通过函数获取
<div :style="appUtil.grayFloatStyle" v-if="appUtil.showGrayFloat()"></div>

/// 通过函数给属性赋值
<div class="singleTag" :style="{backgroundColor:getTagColor(item.oTagInfo.SingleTag.TagColor),borderBottomRightRadius:item.lProMemPrice && item.lProMemPrice>0?'0':'18px'}" v-if="item.oTagInfo&&item.oTagInfo.SingleTag&&item.oTagInfo.SingleTag.TagName">

/// 通过css定义
<div class="wrapper" @click="cancelAddressSelect">

<style scoped>
  .wrapper {
    position: absolute;
    top: -100px;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
  }

  .address_selector {
    background-color: #fff;
    position: absolute;
    bottom: 0;
    left: 0;
    width: 750px;
    height: 640px;
    border-top-right-radius: 20px;
    border-top-left-radius: 20px;
    overflow: hidden;
  }
</style>

/// 通过函数表达式获取值

给视图元素增加事件

/// @事件="函数(arvgs...)"
<image :src="local_image.icon_sending_cancel" class="cancelBtn" @click="closeDialog()"></image>
<input class="inputText" maxlength="30" @input="aliAccountInput" :value="aliaccount" @change="aliAccountInput"/>
<list v-if="hasLoadData" style="flex: 1; width: 750px; margin-top: -1px;" @loadmore="onloadMoreHandle" @scroll="onScroll">
<div class="slider-pages" v-for="(item, i) in bannerList" :key="I" @click="jumpToActivePage(item,'banner',i)" @appear="appear(item,i)">
<app_dialog v-if="isShowNewGiftReceiveFailDialog" tipMsgText="请重试" messageText="领取失败" confirmText="确定" v-on:confirmClick="confirmReceiveGiftPackageDialog"></app_dialog>
    <div v-if="isShowNewGiftReceiveSuccessDialog" style="width: 750px; position: absolute; top: -88px; left: 0; bottom: 0; background-color: rgba(0,0,0,0); justify-content: center; align-items: center;">
      <div style="width: 180px; height: 180px; justify-content: center; align-items: center;background-color: rgba(0,0,0,0.8); border-radius: 12px;">
        <image style="width: 80px;height: 80px; margin-bottom: 20px;" :src="remote_image.receive_success"></image>
        <text style="font-size: 24px; color: #fff; text-align: center;">领取成功</text>
      </div>
    </div>

处理圆角等超出显示范围的时候显示效果配置的属性overflow   https://www.w3school.com.cn/css/pr_pos_overflow.asp

 

给元素绑定别名,用于后续获取

/// ref
<div v-if="showPromoteDialog" ref="refPromoteDialog" class="fullScreenDiv prompt_bg">
      <div style="align-items: flex-end">
        <image style="width: 100px; height: 100px; opacity: 0"
               :src="remote_image.close_envelope_btn"
               @click="closePrompt"
               ref="closeImg"></image>
        <image style="margin-top: 10px; width: 520px; height: 780px"
               :src="promoteDialogData.img"
               @click="toPromotePage"
               @load="onPromoteImageLoad"></image>
      </div>
    </div>

const refPromoteDialog = this.$refs.refPromoteDialog;
const closeImg = this.$refs.closeImg;

自定义组件通过props来提供给外部调用设置属性值

<template>
    <div v-if="showDialog" @click="" style="width:750px;position:absolute;top:0;bottom:0;flex:1;">
        <div style="width:750px;position:absolute;top:-88px;bottom:0;background-color:#000000;opacity:0.75;flex:1;">
        </div>
        <div class="tip-bg" style="background-color: #051C4F;">
            <image style="width:534px; height: 586px;position:absolute;" :src="remote_image.dialog_fail_bg"></image>
            <image style="width:318px; height: 262px;margin-top:61px;" :src="remote_image.dialog_fail_headIcon"></image>
            <text class="tip-content">活动已下线,逛逛别的吧~</text>  
            <image style="width:221px; height: 72px;margin-top:46px;" :src="remote_image.dialog_fail_button" @click="onClickOver"></image>
        </div>
    </div>
</template>

<script>
import image from '../../../data/image_index.js';
import myImage from '../../../data/image_b_activity.js';

export default {
    data() {
        return {
            remote_image: myImage.remote
        };
    },
    props: {
        showDialog: {
            type: Boolean,
            default: false,
        }
    },
    methods: {
        onClickOver() {
            this.$emit('onClickOver');
        },
    }
}
</script>

<style scope>
.tip-bg{
    position:absolute;
    top:359px;
    width:534px;
    height:586px;
    margin-top:0px;
    margin-left:108px;
    align-items: center;
}

.tip-title{
    margin-top:2px;
    margin-left: 151px;
    font-family: PingFangSC-Regular;
    color:#000000;
    font-size:34px;
    font-weight: bold;
    line-height: 34px;
    letter-spacing: 0;
}

 .tip-content{
    font-family: FZLTHJW--GB1-0;
    font-size: 24px;
    color: #FFFFFF;
    letter-spacing: 1px;
    text-align: center;
    line-height: 32px;
    text-shadow: 0 2px 3px rgba(0,0,0,0.50);
    margin-top: 19px;
 }
</style>

自定义组件通过$emit给外界提供事件触发方法代理

export default {
    data() {
        return {
            remote_image: myImage.remote
        };
    },
    props: {
        strUid:{
            type: String,
            default: null,
        },
        showDialog: {
            type: Boolean,
            default: false,
        }
    },
    methods: {
        onClickModify() {
            this.$emit('onClickModify');
        },

        onClickSure() {
            this.$emit('onClickSure');
        }
    }
}

 看一下给组件增加事件的文件WXComponent+Events.m

#import "WXComponent+Events.h"
#import "WXComponent.h"
#import "WXComponent_internal.h"
#import "WXSDKInstance.h"
#import "WXComponentManager.h"
#import "WXAssert.h"
#import "WXUtility.h"
#import "WXSDKManager.h"
#import "WXSDKInstance_private.h"
#import "WXDefine.h"
#import "WXRecycleListComponent.h"
#import "WXRecycleListDataManager.h"
#import <objc/runtime.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "WXComponent+PseudoClassManagement.h"
#import "WXCoreBridge.h"

#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

@interface UITouch (WXTouchGestureRecognizer)
@property (nonatomic, strong) NSNumber *wx_identifier;
@property (nonatomic, strong) NSNumber *wx_stopPropagation;
@end

@implementation UITouch (WXTouchGestureRecognizer)
- (NSNumber *)wx_identifier
{
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setWx_identifier:(NSNumber *)wx_identifier
{
    objc_setAssociatedObject(self, @selector(wx_identifier), wx_identifier, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSNumber *)wx_stopPropagation
{
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setWx_stopPropagation:(NSNumber *)wx_stopPropagation
{
    objc_setAssociatedObject(self, @selector(wx_stopPropagation), wx_stopPropagation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

@interface UIGestureRecognizer (WXGesture)
@property (nonatomic, strong) NSNumber *wx_identifier;
@end

@implementation UIGestureRecognizer (WXGesture)
- (NSNumber *)wx_identifier
{
    NSNumber *identifier = objc_getAssociatedObject(self, _cmd);
    if (!identifier) {
        static NSUInteger _gestureIdentifier;
        identifier = @(_gestureIdentifier++);
        self.wx_identifier = identifier;
    }
    
    return identifier;
}

- (void)setWx_identifier:(NSNumber *)wx_identifier
{
    objc_setAssociatedObject(self, @selector(wx_identifier), wx_identifier, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

@interface WXTouchGestureRecognizer : UIGestureRecognizer

@property (nonatomic, assign) BOOL listenTouchStart;
@property (nonatomic, assign) BOOL listenTouchMove;
@property (nonatomic, assign) BOOL listenTouchEnd;
@property (nonatomic, assign) BOOL listenTouchCancel;
@property (nonatomic, assign) BOOL listenPseudoTouch;

- (instancetype)initWithComponent:(WXComponent *)component NS_DESIGNATED_INITIALIZER;

@end

@interface WXEventManager :NSObject
+ (instancetype) sharedManager;
- (BOOL)stopPropagation:(NSString *)instanceId ref:(NSString *)ref type:(NSString *)type params:(NSDictionary *)params;
@end

@implementation WXEventManager

- (instancetype) init
{
    self = [super init];
    return self;
}

+ (instancetype)sharedManager
{
    static id _sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

- (BOOL)stopPropagation:(NSString *)instanceId ref:(NSString *)ref type:(NSString *)type params:(NSDictionary *)params
{
    JSValue *value = [[WXSDKManager bridgeMgr] fireEventWithResult:instanceId ref:ref type:type params:params domChanges:nil];
    
    if ([value.toString isEqualToString:@"true"]) {
        return YES;
    }
    return NO;
}

@end

@implementation WXComponent (Events)

#pragma mark Public

- (void)fireEvent:(NSString *)eventName params:(NSDictionary *)params
{
    [self fireEvent:eventName params:params domChanges:nil];
}

- (void)fireEvent:(NSString *)eventName params:(NSDictionary *)params domChanges:(NSDictionary *)domChanges
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    NSTimeInterval timeSp = [[NSDate date] timeIntervalSince1970] * 1000;
    [dict setObject:@(timeSp) forKey:@"timestamp"];
    if (params) {
        [dict addEntriesFromDictionary:params];
    }
    WXRecycleListComponent *recyleListComponent  = (WXRecycleListComponent*)[self getRecycleListComponent];
    if (recyleListComponent) {
        NSIndexPath *indexPath = [((UICollectionView*)recyleListComponent.view) indexPathForItemAtPoint:[self.view.superview
                                                                                                          convertPoint:self.view.center toView:recyleListComponent.view]];
        NSString *templateId = [self recursiveFindTemplateIdWithComponent:self];
        NSString *virtualComponentId = [recyleListComponent.dataManager virtualComponentIdWithIndexPath:indexPath templateId:templateId];
        if (virtualComponentId) {
            dict[@"componentId"] = virtualComponentId;
        }
    }
    
    NSArray *handlerArguments = [self _paramsForEvent:eventName];
    NSString *ref = _templateComponent ? _templateComponent.ref  : self.ref;
    [[WXSDKManager bridgeMgr] fireEvent:self.weexInstance.instanceId ref:ref type:eventName params:dict domChanges:domChanges handlerArguments:handlerArguments];
}

- (NSString *)recursiveFindTemplateIdWithComponent:(WXComponent *)component
{
    if (!component) {
        return nil;
    }
    if ([component isKindOfClass:NSClassFromString(@"WXCellSlotComponent")]) {
        return nil;
    }
    if (component.attributes[@"@templateId"]) {
        return component.attributes[@"@templateId"];
    }
    return [self recursiveFindTemplateIdWithComponent:component.supercomponent];
}

- (void)addEvent:(NSString *)addEventName
{
    WXAssertMainThread();
}

- (void)removeEvent:(NSString *)removeEventName
{
    WXAssertMainThread();
}

#pragma mark Add & Remove Event

#define WX_ADD_EVENT(eventName, addSelector) \
if ([addEventName isEqualToString:@#eventName]) {\
    [self addSelector];\
}

#define WX_ADD_EVENTS(eventName1,eventName2, addSelector) \
if ([addEventName isEqualToString:@#eventName1]||[addEventName isEqualToString:@#eventName2]) {\
    [self addSelector:addEventName];\
}

#define WX_REMOVE_EVENT(eventName, removeSelector) \
if ([removeEventName isEqualToString:@#eventName]) {\
    [self removeSelector];\
}

#define WX_REMOVE_EVENTS(eventName1,eventName2, removeSelector) \
if ([removeEventName isEqualToString:@#eventName1]||[removeEventName isEqualToString:@#eventName2]) {\
    [self removeSelector];\
}

- (void)_initEvents:(NSArray *)events
{
    for (NSString *addEventName in events) {
        [self _addEventOnMainThread:addEventName];
    }
}

- (void)_initPseudoEvents:(BOOL)isListenPseudoTouch
{
    if(isListenPseudoTouch) {
        self.touchGesture.listenPseudoTouch = YES;
    }
}

- (void)_addEventOnMainThread:(NSString *)addEventName
{
    if (![self isViewLoaded]) {
        //This action will be ignored While the view is loaded,
        //then it will initEvent according to the records in _events
        return;
    }
    WX_ADD_EVENT(appear, addAppearEvent)
    WX_ADD_EVENT(disappear, addDisappearEvent)
    
    WX_ADD_EVENT(click, addClickEvent)
    WX_ADD_EVENT(swipe, addSwipeEvent)
    WX_ADD_EVENT(longpress, addLongPressEvent)
    
    WX_ADD_EVENT(panstart, addPanStartEvent)
    WX_ADD_EVENT(panmove, addPanMoveEvent)
    WX_ADD_EVENT(panend, addPanEndEvent)
    
    WX_ADD_EVENT(horizontalpan, addHorizontalPanEvent)
    WX_ADD_EVENT(verticalpan, addVerticalPanEvent)
    
    WX_ADD_EVENT(touchstart, addTouchStartEvent)
    WX_ADD_EVENT(touchmove, addTouchMoveEvent)
    WX_ADD_EVENT(touchend, addTouchEndEvent)
    WX_ADD_EVENT(touchcancel, addTouchCancelEvent)
    WX_ADD_EVENT(accessibilityMagicTap, addAccessibilityMagicTapEvent)
    
    WX_ADD_EVENTS(stopPropagation, stoppropagation, addStopPropagationEvent)
    
    if(_isListenPseudoTouch) {
        self.touchGesture.listenPseudoTouch = YES;
    }
    
    [self addEvent:addEventName];
}

- (void)_removeEventOnMainThread:(NSString *)removeEventName
{
    WX_REMOVE_EVENT(appear, removeAppearEvent)
    WX_REMOVE_EVENT(disappear, removeDisappearEvent)
    
    WX_REMOVE_EVENT(click, removeClickEvent)
    WX_REMOVE_EVENT(swipe, removeSwipeEvent)
    WX_REMOVE_EVENT(longpress, removeLongPressEvent)
    
    WX_REMOVE_EVENT(panstart, removePanStartEvent)
    WX_REMOVE_EVENT(panmove, removePanMoveEvent)
    WX_REMOVE_EVENT(panend, removePanEndEvent)
    
    WX_REMOVE_EVENT(horizontalpan, removeHorizontalPanEvent)
    WX_REMOVE_EVENT(verticalpan, removeVerticalPanEvent)
    
    WX_REMOVE_EVENT(touchstart, removeTouchStartEvent)
    WX_REMOVE_EVENT(touchmove, removeTouchMoveEvent)
    WX_REMOVE_EVENT(touchend, removeTouchEndEvent)
    WX_REMOVE_EVENT(touchcancel, removeTouchCancelEvent)
    WX_REMOVE_EVENT(accessibilityMagicTap, removeAccessibilityMagicTapEvent)
    
    WX_REMOVE_EVENTS(stoppropagation,stopPropagation, removeStopPropagationEvent)

    if(_isListenPseudoTouch) {
        self.touchGesture.listenPseudoTouch = NO;
    }

    [self removeEvent:removeEventName];
}

- (void)_removeAllEvents
{
    [self removeClickEvent];
    [self removeLongPressEvent];
    [self removePanStartEvent];
    [self removePanMoveEvent];
    [self removePanEndEvent];
    [self removeHorizontalPanEvent];
    [self removeVerticalPanEvent];
    
    [self removeTouchStartEvent];
    [self removeTouchMoveEvent];
    [self removeTouchEndEvent];
    [self removeTouchCancelEvent];
    [self removeSwipeEvent];
    [self removePseudoTouchEvent];
}

- (void)_collectSubcomponents:(NSMutableArray *)components
{
    for (WXComponent* c in _subcomponents) {
        [components addObject:c];
        [c _collectSubcomponents:components];
    }
}

#pragma mark - Appear & Disappear

- (void)addAppearEvent
{
    _appearEvent = YES;
    [self.ancestorScroller addScrollToListener:self];
}

- (void)addDisappearEvent
{
    _disappearEvent = YES;
    [self.ancestorScroller addScrollToListener:self];
}

- (void)removeAppearEvent
{
    _appearEvent = NO;
    [self.ancestorScroller removeScrollToListener:self];
}

- (void)removeDisappearEvent
{
    _disappearEvent = NO;
    [self.ancestorScroller removeScrollToListener:self];
}

- (void)removePseudoTouchEvent
{
    _touchGesture.listenPseudoTouch = NO;
    [self checkRemoveTouchGesture];
}

#pragma mark - Accessibility Event

- (void)addAccessibilityMagicTapEvent
{
    _accessibilityMagicTapEvent = YES;
}

- (void)removeAccessibilityMagicTapEvent
{
    _accessibilityMagicTapEvent = NO;
}

#pragma mark - StopPropagation

- (void)addStopPropagationEvent:(NSString *)stopPropagationName
{
    _listenStopPropagation = YES;
    _stopPropagationName = stopPropagationName;
    self.touchGesture.listenTouchMove = YES;
}

- (void)removeStopPropagationEvent
{
    _listenStopPropagation = NO;
    self.touchGesture.listenTouchMove = NO;
}

#pragma mark - Click Event

- (void)addClickEvent
{
    if (!_tapGesture) {
        _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick:)];
        _tapGesture.delegate = self;
        _tapGesture.cancelsTouchesInView = _cancelsTouchesInView;
        [self.view addGestureRecognizer:_tapGesture];
    }
}

- (void)removeClickEvent
{
    if (_tapGesture) {
        _tapGesture.delegate = nil;
        if ([self isViewLoaded]) {
            if ([self.view.gestureRecognizers containsObject:_tapGesture]) {
                [self.view removeGestureRecognizer:_tapGesture];
            }
        }
        @try {
            [_tapGesture removeTarget:self action:@selector(onClick:)];
        }@catch(NSException *exception) {
            WXLog(@"%@", exception);
        }
        _tapGesture = nil;
    }
}

- (void)onClick:(__unused UITapGestureRecognizer *)recognizer
{
    NSMutableDictionary *position = [[NSMutableDictionary alloc] initWithCapacity:4];
    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
    if (![self isViewLoaded]) {
        return;
    }
    if (!CGRectEqualToRect(self.view.frame, CGRectZero)) {
        CGRect frame = [self.view.superview convertRect:self.view.frame toView:self.view.window];
        position[@"x"] = @(frame.origin.x/scaleFactor);
        position[@"y"] = @(frame.origin.y/scaleFactor);
        position[@"width"] = @(frame.size.width/scaleFactor);
        position[@"height"] = @(frame.size.height/scaleFactor);
    }
    [self fireEvent:@"click" params:@{@"position":position}];
}

#pragma mark - Swipe event

- (void)addSwipeEvent
{
    if (_swipeGestures) {
        return;
    }
    
    _swipeGestures = [NSMutableArray arrayWithCapacity:4];
    
    // It's a little weird because the UISwipeGestureRecognizer.direction property is an options-style bit mask, but each recognizer can only handle one direction
    SEL selector = @selector(onSwipe:);
    UISwipeGestureRecognizer *upSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                            action:selector];
    upSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
    upSwipeRecognizer.delegate = self;
    [_swipeGestures addObject:upSwipeRecognizer];
    [self.view addGestureRecognizer:upSwipeRecognizer];
    
    UISwipeGestureRecognizer *downSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                              action:selector];
    downSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
    downSwipeRecognizer.delegate = self;
    [_swipeGestures addObject:downSwipeRecognizer];
    [self.view addGestureRecognizer:downSwipeRecognizer];
    
    UISwipeGestureRecognizer *rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                               action:selector];
    rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    rightSwipeRecognizer.delegate = self;
    [_swipeGestures addObject:rightSwipeRecognizer];
    [self.view addGestureRecognizer:rightSwipeRecognizer];
    
    UISwipeGestureRecognizer *leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                              action:selector];
    leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    leftSwipeRecognizer.delegate = self;
    [_swipeGestures addObject:leftSwipeRecognizer];
    [self.view addGestureRecognizer:leftSwipeRecognizer];
}

- (void)removeSwipeEvent
{
    if (_swipeGestures == nil) {
        return;
    }
  
    @try {
        for (UISwipeGestureRecognizer *recognizer in _swipeGestures) {
            recognizer.delegate = nil;
            if([self isViewLoaded]) {
                if ([[self.view gestureRecognizers] containsObject:recognizer]) {
                    [self.view removeGestureRecognizer:recognizer];
                }
            }
            [recognizer removeTarget:self action:@selector(onSwipe:)];
        }
    }@catch(NSException *exception) {
        WXLog(@"%@", exception);
    }
    _swipeGestures = nil;
}

- (void)onSwipe:(UISwipeGestureRecognizer *)gesture
{
    if (![self isViewLoaded]) {
        return;
    }
    
    UISwipeGestureRecognizerDirection direction = gesture.direction;
    
    NSString *directionString;
    switch(direction) {
        case UISwipeGestureRecognizerDirectionLeft:
            directionString = @"left";
            break;
        case UISwipeGestureRecognizerDirectionRight:
            directionString = @"right";
            break;
        case UISwipeGestureRecognizerDirectionUp:
            directionString = @"up";
            break;
        case UISwipeGestureRecognizerDirectionDown:
            directionString = @"down";
            break;
        default:
            directionString = @"unknown";
            break;
    }
    
    CGPoint screenLocation = [gesture locationInView:self.view.window];
    CGPoint pageLoacation = [gesture locationInView:self.weexInstance.rootView];
    NSDictionary *resultTouch = [self touchResultWithScreenLocation:screenLocation pageLocation:pageLoacation identifier:gesture.wx_identifier];
    [self fireEvent:@"swipe" params:@{@"direction":directionString, @"changedTouches":resultTouch ? @[resultTouch] : @[]}];
}

#pragma mark - Long Press

- (void)addLongPressEvent
{
    if (!_longPressGesture) {
        _longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)];
        _longPressGesture.delegate = self;
        [self.view addGestureRecognizer:_longPressGesture];
    }
}

- (void)removeLongPressEvent
{
    if (_longPressGesture) {
        _longPressGesture.delegate = nil;
        if ([self isViewLoaded]) {
            if([[self.view gestureRecognizers] containsObject:_longPressGesture]) {
                [self.view removeGestureRecognizer:_longPressGesture];
            }
        }
        @try {
            [_longPressGesture removeTarget:self action:@selector(onLongPress:)];
        }@catch(NSException * exception) {
            WXLog(@"%@", exception);
        }
        _longPressGesture = nil;
    }
}

- (void)onLongPress:(UILongPressGestureRecognizer *)gesture
{
    if (![self isViewLoaded]) {
        return;
    }
    
    if (gesture.state == UIGestureRecognizerStateBegan) {
        CGPoint screenLocation = [gesture locationInView:self.view.window];
        CGPoint pageLoacation = [gesture locationInView:self.weexInstance.rootView];
        NSDictionary *resultTouch = [self touchResultWithScreenLocation:screenLocation pageLocation:pageLoacation identifier:gesture.wx_identifier];
        [self fireEvent:@"longpress" params:@{@"changedTouches":resultTouch ? @[resultTouch] : @[]}];
    } else if (gesture.state == UIGestureRecognizerStateEnded) {
        gesture.wx_identifier = nil;
    }
}

#pragma mark - Pan

- (void)addPanGesture
{
    if (!_panGesture) {
        _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPan:)];
        _panGesture.delegate = self;
        [self.view addGestureRecognizer:_panGesture];
    }
}

- (void)addPanStartEvent
{
    _listenPanStart = YES;
    [self addPanGesture];
}

- (void)addPanMoveEvent
{
    _listenPanMove = YES;
    [self addPanGesture];
}

- (void)addPanEndEvent
{
    _listenPanEnd = YES;
    [self addPanGesture];
}

- (void)addHorizontalPanEvent
{
    _listenHorizontalPan = YES;
    [self addPanGesture];
}

- (void)addVerticalPanEvent
{
    _listenVerticalPan = YES;
    [self addPanGesture];
}


- (void)onPan:(UIPanGestureRecognizer *)gesture
{
    if (![self isViewLoaded]) {
        return;
    }
    
    CGPoint screenLocation = [gesture locationInView:self.view.window];
    CGPoint pageLoacation = [gesture locationInView:self.weexInstance.rootView];
    NSString *eventName;
    NSString *state = @"";
    NSDictionary *resultTouch = [self touchResultWithScreenLocation:screenLocation pageLocation:pageLoacation identifier:gesture.wx_identifier];
    
    if (gesture.state == UIGestureRecognizerStateBegan) {
        if (_listenPanStart) {
            eventName = @"panstart";
        }
        state = @"start";
    } else if (gesture.state == UIGestureRecognizerStateEnded) {
        if (_listenPanEnd) {
            eventName = @"panend";
        }
        state = @"end";
        gesture.wx_identifier = nil;
    } else if (gesture.state == UIGestureRecognizerStateChanged) {
        if (_listenPanMove) {
             eventName = @"panmove";
        }
        state = @"move";
    } else if (gesture.state == UIGestureRecognizerStateCancelled) {
        state = @"cancel";
    }
    
    CGPoint translation = [_panGesture translationInView:self.view];
    
    if (_listenHorizontalPan && (gesture.state != UIGestureRecognizerStateBegan || fabs(translation.y) <= fabs(translation.x))) {
        [self fireEvent:@"horizontalpan" params:@{@"state":state, @"changedTouches":resultTouch ? @[resultTouch] : @[]}];
    }
        
    if (_listenVerticalPan && (gesture.state != UIGestureRecognizerStateBegan || fabs(translation.y) >= fabs(translation.x))) {
        [self fireEvent:@"verticalpan" params:@{@"state":state, @"changedTouches":resultTouch ? @[resultTouch] : @[]}];
    }
        
    if (eventName) {
        [self fireEvent:eventName params:@{@"changedTouches":resultTouch ? @[resultTouch] : @[]}];
    }
}

- (void)removePanStartEvent
{
    _listenPanStart = NO;
    [self checkRemovePanGesture];
}

- (void)removePanMoveEvent
{
    _listenPanMove = NO;
    [self checkRemovePanGesture];
}

- (void)removePanEndEvent
{
    _listenPanEnd = NO;
    [self checkRemovePanGesture];
}

- (void)removeHorizontalPanEvent
{
    _listenHorizontalPan = NO;
    [self checkRemovePanGesture];
}

- (void)removeVerticalPanEvent
{
    _listenVerticalPan = NO;
    [self checkRemovePanGesture];
}

- (void)checkRemovePanGesture
{
    if (_panGesture
        && !_listenPanStart && !_listenPanMove && !_listenPanEnd
        && !_listenHorizontalPan && !_listenVerticalPan
        ) {
        
        if ([self isViewLoaded]) {
            if ([[self.view gestureRecognizers] containsObject:_panGesture]) {
                [self.view removeGestureRecognizer:_panGesture];
            }
        }
        
        _panGesture.delegate = nil;
        @try {
            [_panGesture removeTarget:self action:@selector(onPan:)];
        }@catch(NSException * exception) {
            WXLog(@"%@", exception);
        }
        _panGesture = nil;
    }
}

#pragma mark - Touch Event

- (WXTouchGestureRecognizer *)touchGesture
{
    if (!_touchGesture) {
        _touchGesture = [[WXTouchGestureRecognizer alloc] initWithComponent:self];
        _touchGesture.delegate = self;
        [self.view addGestureRecognizer:_touchGesture];
    }
    return _touchGesture;
}

- (void)addTouchStartEvent
{
    self.touchGesture.listenTouchStart = YES;
}

- (void)addTouchMoveEvent
{
    self.touchGesture.listenTouchMove = YES;
}

- (void)addTouchEndEvent
{
    self.touchGesture.listenTouchEnd = YES;
}

- (void)addTouchCancelEvent
{
    self.touchGesture.listenTouchCancel = YES;
}

- (void)removeTouchStartEvent
{
    _touchGesture.listenTouchStart = NO;
    [self checkRemoveTouchGesture];
}

- (void)removeTouchMoveEvent
{
    _touchGesture.listenTouchMove = NO;
    [self checkRemoveTouchGesture];
}

- (void)removeTouchEndEvent
{
    _touchGesture.listenTouchEnd = NO;
    [self checkRemoveTouchGesture];
}

- (void)removeTouchCancelEvent
{
    _touchGesture.listenTouchCancel = NO;
    [self checkRemoveTouchGesture];
}

- (void)checkRemoveTouchGesture
{
    if (_touchGesture && !_touchGesture.listenTouchStart && !_touchGesture.listenTouchMove && !_touchGesture.listenTouchEnd && !_touchGesture.listenTouchCancel && !_touchGesture.listenPseudoTouch) {
        _touchGesture.delegate = nil;
        if ([self isViewLoaded]) {
            if ([[self.view gestureRecognizers] containsObject:_touchGesture]) {
                [self.view removeGestureRecognizer:_touchGesture];
            }
        }
        _touchGesture = nil;
    }
}

- (BOOL)gestureShouldStopPropagation:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if(touch.wx_stopPropagation && [touch.wx_stopPropagation isEqualToNumber:@1]){
        return NO;
    }
    else
    {
        if (_listenStopPropagation)
        {
            NSString *ref = _templateComponent ? _templateComponent.ref : self.ref;
            CGPoint screenLocation = [touch locationInView:touch.window];
            CGPoint pageLocation = [touch locationInView:self.weexInstance.rootView];
            NSDictionary *resultTouch = [self touchResultWithScreenLocation:screenLocation pageLocation:pageLocation identifier:touch.wx_identifier];
            NSString *touchState;
            if (touch.phase == UITouchPhaseBegan) {
                touchState = @"start";
            }
            else if (touch.phase == UITouchPhaseMoved){
                touchState = @"move";
            }
            else{
                touchState = @"end";
            }
            BOOL stopPropagation = [[WXEventManager sharedManager]stopPropagation:self.weexInstance.instanceId ref:ref type:_stopPropagationName params:@{@"changedTouches":resultTouch ? @[resultTouch] : @[],@"action":touchState}];
            touch.wx_stopPropagation = stopPropagation ? @1 : @0;
            
            //only custom event on custom component will make not receive touch
            //you can use custom-event="yes" to enable this feature
            return _customEvent ? !stopPropagation : YES;
        }
    }
    return YES;
}

#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return [self gestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == _panGesture) {
        CGPoint translation = [_panGesture translationInView:self.view];
        if (_listenHorizontalPan && !_listenVerticalPan && fabs(translation.y) > fabs(translation.x)) {
            return NO;
        }
    }
    return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    NSString * panGestureRecog = [NSString stringWithFormat:@"%@%@%@%@%@%@",@"UIScrollV", @"iewPanG", @"estur",@"eRecog",@"nize",@"r"];
    NSString * textTap = [NSString stringWithFormat:@"%@%@%@%@%@",@"UITe",@"xtTa",@"pReco",@"gniz",@"er"];
    // trigger touches
    if ([gestureRecognizer isKindOfClass:[WXTouchGestureRecognizer class]]) {
        return YES;
    }
    // swipe and scroll
    if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:NSClassFromString(panGestureRecog)]) {
        return YES;
    }
    // onclick and textviewInput
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass: NSClassFromString(textTap)]) {
        return YES;
    }
    
    return NO;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
        [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        if (otherGestureRecognizer.state != UIGestureRecognizerStateFailed) {
            if ([gestureRecognizer view].wx_component != nil && [otherGestureRecognizer view].wx_component != nil) {
                return YES;
            }
        }
    }
    
    return NO;
}

#pragma mark - Utils

- (NSDictionary *)touchResultWithScreenLocation:(CGPoint)screenLocation pageLocation:(CGPoint)pageLocation identifier:(NSNumber *)identifier
{
    NSMutableDictionary *resultTouch = [[NSMutableDictionary alloc] initWithCapacity:5];
    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
    resultTouch[@"screenX"] = @(screenLocation.x/scaleFactor);
    resultTouch[@"screenY"] = @(screenLocation.y/scaleFactor);
    resultTouch[@"pageX"] = @(pageLocation.x/scaleFactor);
    resultTouch[@"pageY"] = @(pageLocation.y/scaleFactor);
    resultTouch[@"identifier"] = identifier;
    
    return resultTouch;
}

// find virtual component's root component
- (WXComponent*)getRecycleListComponent
{
    if ([self isKindOfClass:[WXRecycleListComponent class]]) {
        return self;
    }
    if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
        return nil;
    }
    return [self.supercomponent getRecycleListComponent];
}

@end

@implementation WXTouchGestureRecognizer
{
    __weak WXComponent *_component;
    NSUInteger _touchIdentifier;
}

- (instancetype)initWithTarget:(id)target action:(SEL)action
{
    return [self initWithComponent:nil];
}

- (instancetype)initWithComponent:(WXComponent *)component
{
    if (self = [super initWithTarget:self action:@selector(touchResponse:)]) {
        _component = component;
        
        _listenTouchStart = NO;
        _listenTouchEnd = NO;
        _listenTouchMove = NO;
        _listenTouchCancel = NO;
        
        self.cancelsTouchesInView = NO;
    }
    
    return self;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    
    if (_listenTouchStart) {
        [self fireTouchEvent:@"touchstart" withTouches:touches];
    }
    if(_listenPseudoTouch) {
        NSMutableDictionary *styles = [_component getPseudoClassStyles:@"active"];
        [_component updatePseudoClassStyles:styles];
    }

}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    
    if (_listenTouchMove) {
        [self fireTouchEvent:@"touchmove" withTouches:touches];
    }
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    [super touchesEnded:touches withEvent:event];
    
    if (_listenTouchEnd) {
        [self fireTouchEvent:@"touchend" withTouches:touches];
    }
    if(_listenPseudoTouch) {
        [self recoveryPseudoStyles:_component.styles];
    }

}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    
    if (_listenTouchCancel) {
        [self fireTouchEvent:@"touchcancel" withTouches:touches];
    }
    if(_listenPseudoTouch) {
        [self recoveryPseudoStyles:_component.styles];
    }
}

- (void)fireTouchEvent:(NSString *)eventName withTouches:(NSSet<UITouch *> *)touches
{
    if (_component == nil) {
        return;
    }
    
    NSMutableArray *resultTouches = [NSMutableArray new];
    
    CGPoint accmOffset = CGPointZero;
    UIView* rootView = _component.weexInstance.rootView;
//    UIView* view = self.view;
//    while (view && view != rootView) {
//        if ([view isKindOfClass:[UIScrollView class]]) {
//            CGPoint offset = ((UIScrollView*)view).contentOffset;
//            accmOffset.x += offset.x;
//            accmOffset.y += offset.y;
//        }
//        view = view.superview;
//    }
    
    for (UITouch *touch in touches) {
        CGPoint screenLocation = [touch locationInView:touch.window];
        CGPoint pageLocation = [touch locationInView:rootView];
        pageLocation.x += accmOffset.x;
        pageLocation.y += accmOffset.y;
      
        if (!touch.wx_identifier) {
            touch.wx_identifier = @(_touchIdentifier++);
        }
        NSDictionary *resultTouch = [_component touchResultWithScreenLocation:screenLocation pageLocation:pageLocation identifier:touch.wx_identifier];
        NSMutableDictionary * mutableResultTouch = [resultTouch mutableCopy];
        
        float value = touch.force*60;
        float maxValue = touch.maximumPossibleForce*60;
        if (touch.maximumPossibleForce) {
            // the forece value will be range 1 from 0.
            [mutableResultTouch setObject:[NSNumber numberWithFloat:value/maxValue] forKey:@"force"];
        }else {
            [mutableResultTouch setObject:[NSNumber numberWithFloat:0.0] forKey:@"force"];
        }
        
        if (mutableResultTouch) { // component is nil, mutableResultTouch will be nil
            [resultTouches addObject:mutableResultTouch];
        }
    }
    
    [_component fireEvent:eventName params:@{@"changedTouches":resultTouches ?: @[]}];
}

- (void)recoveryPseudoStyles:(NSDictionary *)styles
{
    [_component recoveryPseudoStyles:styles];
}

- (void)touchResponse:(UIGestureRecognizer *)gesture
{
    
}

@end

 weex中Vue设置空间样式,使用style=""、:style="{}"、class="" 三者是有一些区别的 使用中发现在一个负责一些的页面上 flex设置显示了三种不同的效果,其中class=""是期望的效果

posted @ 2020-12-31 18:01  雨筱逸悠  阅读(253)  评论(0编辑  收藏  举报