启动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; 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=" 750px; position: absolute; top: -88px; left: 0; bottom: 0; background-color: rgba(0,0,0,0); justify-content: center; align-items: center;"> <div style=" 180px; height: 180px; justify-content: center; align-items: center;background-color: rgba(0,0,0,0.8); border-radius: 12px;"> <image style=" 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=" 100px; height: 100px; opacity: 0" :src="remote_image.close_envelope_btn" @click="closePrompt" ref="closeImg"></image> <image style="margin-top: 10px; 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="750px;position:absolute;top:0;bottom:0;flex:1;"> <div style="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="534px; height: 586px;position:absolute;" :src="remote_image.dialog_fail_bg"></image> <image style="318px; height: 262px;margin-top:61px;" :src="remote_image.dialog_fail_headIcon"></image> <text class="tip-content">活动已下线,逛逛别的吧~</text> <image style="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=""是期望的效果