软件编程
位置:首页>> 软件编程>> flutter编程>> 大前端代码重构之事件拦截iOS Flutter Vue示例分析

大前端代码重构之事件拦截iOS Flutter Vue示例分析

作者:SoaringHeart  发布时间:2021-12-11 20:16:53 

标签:前端重构,事件拦截,iOS,Flutter,vue

一、需求来源

app需要支持实现游客模式,启动后直接进入首页菜单,但是进入二级页则自动调用登录页面。总结需求就是父视图拦截子视图的响应事件,思考之后发现在事件响应链上做拦截是最优方法。

大前端代码重构之事件拦截iOS Flutter Vue示例分析

二、iOS 事件拦截

1、使用示例

absorbing 属性为 true 时,会拦截子视图的事件。点击 button 时只会调用 absorbPointerView(绿色) 的响应方法。

absorbing 属性为 false 时,不会拦截子视图的事件。点击 button 时只会调用 button(蓝色)的响应方法。

大前端代码重构之事件拦截iOS Flutter Vue示例分析

import UIKit
import SnapKit
import SwiftExpand
/**
通过递归遍历将所有子视图设置 isUserInteractionEnabled = false,则该视图可以响应事件;
*/
class NNAbsorbPointerViewController: UIViewController {
   override func viewDidLoad() {
       super.viewDidLoad()
       // Do any additional setup after loading the view.
       edgesForExtendedLayout = []
       view.backgroundColor = .white
       title = "NNAbsorbPointerView"
       absorbPointerView.addSubview(button)
       view.addSubview(absorbPointerView)
//        view.recursion{ e in
//            e.isUserInteractionEnabled = false;
//        }
       view.addGestureTap { reco in
           debugPrint("\(Date()):reco.view")
       }
   }
   override func viewDidLayoutSubviews() {
       super.viewDidLayoutSubviews()
       let edge = UIEdgeInsets(all: 50)
       button.snp.makeConstraints { make in
           make.edges.equalToSuperview().inset(edge)
       }
       absorbPointerView.snp.makeConstraints { make in
           make.edges.equalToSuperview().inset(edge)
       }
   }
   lazy var absorbPointerView: NNAbsorbPointerView = {
       let view = NNAbsorbPointerView(frame: .zero);
       view.absorbing = true;
       view.backgroundColor = .green;
       view.addGestureTap { reco in
           debugPrint("\(Date()):NNAbsorbPointerView")
       }
       return view
   }()
   lazy var button: UIButton = {
       let view = UIButton(type: .custom);
       view.setTitle("UIButton", for: .normal)
       view.setTitleColor(.white, for: .normal)
       view.backgroundColor = .blue;
       view.addGestureTap { reco in
           debugPrint("\(Date()):button")
       }
       return view
   }()
}

2、自定义视图 NNAbsorbPointerView,用来拦截它子视图事件。

import UIKit
class NNAbsorbPointerView: UIView {
   /// 是否拦截响应
   var absorbing = false;
   // **MARK: - 重写加载方法**
   override init(frame: CGRect) {
       super.init(frame: frame);
   }
   required init?(coder: NSCoder) {
       fatalError("init(coder:) has not been implemented")
   }
   override func layoutSubviews() {
       super.layoutSubviews()
   }
   override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
       if absorbing {
           return self
       }
       // 1.判断能不能处理事件
       if isUserInteractionEnabled == false, isHidden, alpha <= 0.01 {
           return nil
       }
       // 2.判断点在不在当前控件上
       if self.point(inside: point, with: event) == false {
           return nil;
       }
       for subView in subviews.reversed() {
           let subPoint = self.convert(point, to: subView);
           if let targetView = subView.hitTest(subPoint, with: event) {
               return targetView;
           }
       }
       return self
   }
   // **MARK: - 私有方法**
}

三、Flutter 事件拦截

1、使用示例

absorbing 属性为 true 时,会拦截子视图的事件。点击蓝色 Container 时只会调用绿色 Container 的响应方法。

absorbing 属性为 false 时,不会拦截子视图的事件。点击蓝色 Container 时只会调用蓝色 Container 的响应方法。

大前端代码重构之事件拦截iOS Flutter Vue示例分析

//
//  AbsorbPointerDemo.dart
//  flutter_templet_project
//
//  Created by shang on 10/25/21 11:05 AM.
//  Copyright © 10/25/21 shang. All rights reserved.
//
// AbsorbPointer本身可以接收点击事件,消耗掉事件,而IgnorePointer无法接收点击事件,其下的控件可以接收到点击事件(不是子控件)。
import "package:flutter/material.dart";
import 'package:flutter_templet_project/extension/ddlog.dart';
class AbsorbPointerDemo extends StatefulWidget {
 const AbsorbPointerDemo({Key? key}) : super(key: key);
 @override
 _AbsorbPointerDemoState createState() => _AbsorbPointerDemoState();
}
class _AbsorbPointerDemoState extends State<AbsorbPointerDemo> {
 bool _disable = false;
 bool _switchValue = false;
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Absorbpointer'),
       centerTitle: true,
       elevation: 0,
     ),
     body: Column(
       mainAxisAlignment: MainAxisAlignment.start,
       children: <Widget>[
         Row(
           children: <Widget>[
             Text('不可点击:absorbing: ${_disable}'),
             Switch(
               value: _disable,
               onChanged: (bool val) {
                 _disable = val;
                 setState(() {});
               },
             )
           ],
         ),
         Divider(),
         _buildAbsorbPointerNew(absorbing: _disable),
         MaterialButton(
           color: Colors.lightBlue,
           onPressed: () => onClick('我是外面的按钮,不受影响'),
           child: Text('我是外面的按钮,不受影响'),
         ),
       ],
     ),
   );
 }
 /// 默认吸收事件,拦截事件
 _buildAbsorbPointerNew({bool absorbing = true}) {
   return InkWell(
     onTap: () => onClick("outside"),
     child: Container(
       color: Colors.green,
       padding: EdgeInsets.all(20),
       child: AbsorbPointer(
         absorbing: absorbing,
         child: InkWell(
           onTap: () => onClick("inside"),
           child: Container(
             color: Colors.blue,
             width: 200.0,
             height: 100.0,
             alignment: Alignment.center,
             child: Text("Container"),
           ),
         ),
       ),
     ),
   );
 }
 onClick(String msg) {
   debugPrint(msg);
 }
}

四、Web 事件拦截

1、Vue 事件拦截

实现很简单,@click 添加修饰符 capture.stop 即可拦截子标签事件。

点击 button 时,父视图(绿色)会拦截响应事件。

大前端代码重构之事件拦截iOS Flutter Vue示例分析

<template>
 <h2>{{ $route.meta.title }}</h2>
 <!-- <h2>{{ JSON.stringify(route) }}</h2> -->
 <div class="page" @click.capture.stop="doThis">
   <button @click="onClick">button</button>
 </div>
</template>
<script setup>
import { getCurrentInstance, ref, reactive, watch, onMounted, } from 'vue';
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
const doThis = () => {
 console.log(`${new Date()}: doThis`);
};
const onClick = () => {
 console.log(`${new Date()}: onClick`);
};
</script>
<style scoped lang='scss'>
.page{
 background-color: green;
}
</style>

2、react 事件拦截

暂无

3、angular 事件拦截

暂无

最后、总结

1、iOS 还有一种办法,递归遍历所有子视图进行处理,让其不响应事件,事件自然会传递到 目标父视图,只是性能较差;

2、Flutter 中随组件类型不同有略微差距,使用时需要根据实际情况调试。

3、大前端思路都是通的,事件机制一端弄懂了就三端都差不多了,细微差距可以在实际开发中再思考总结。以后大前端加一门后端技能是时代趋势,Keep Learning!!!

AbsorbPointerDemo.dart

NNAbsorbPointerViewController.swift

EventIntercept.vue

来源:https://juejin.cn/post/7217755581846716471

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com