大前端代码重构之事件拦截iOS Flutter Vue示例分析
作者:SoaringHeart 发布时间:2021-12-11 20:16:53
一、需求来源
app需要支持实现游客模式,启动后直接进入首页菜单,但是进入二级页则自动调用登录页面。总结需求就是父视图拦截子视图的响应事件,思考之后发现在事件响应链上做拦截是最优方法。
二、iOS 事件拦截
1、使用示例
absorbing 属性为 true 时,会拦截子视图的事件。点击 button 时只会调用 absorbPointerView(绿色) 的响应方法。
absorbing 属性为 false 时,不会拦截子视图的事件。点击 button 时只会调用 button(蓝色)的响应方法。
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 的响应方法。
//
// 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 时,父视图(绿色)会拦截响应事件。
<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
猜你喜欢
- 目录一、handler基本认识1、基本组成2、基本使用方法3、工作流程二、发送消息三、消息进入消息队列1、入队前的准备工作2、将消息加入队列
- 一、二进制读写类:1、BinaryReader/BinaryWriter:二进制读写BinaryReader:用特定的编码将基元数据类型读作
- 一、pom.xml引入相关模块web、jpa、thymeleaf、oracle:<dependency> &nbs
- 疑问,确实像往常一样在service上添加了注解 @Transactional,为什么查询数据库时还是发现有数据不一致的情况,想想肯定是事务
- C#时间显示格式一起看下:24小时制this.toolStripStatusLabel1.Text = “您好,欢迎来到XXXX控制系统!”
- 第一次进入应用的时候,都会有一个引导页面,引导页面的实现起来也很简单,实现的方式也有很多,下面是自己写的一个引导页面的效果,大致的实现思路为
- 对开场白没兴趣?好吧,我们直接切入正题,下面介绍10个C#编程和Visual Studio IDE使用技巧。1、Environment.Ne
- Runtime.getRuntime().exec 路径包含空格1. 现象java代码通过Runtime.getRuntime().exec
- 前言:最新Servlet 3.0 * 的使用1.pom.xml添加需要使用的依赖<project xmlns="http:/
- 先介绍一下API,与其他文章不同的是,本文采取类比的方式来讲,同时结合源码。而不像其他文章一样,一个个API罗列出来,让人找不到重点。1、O
- 1、Spring的事务管理主要包括3个接口TransactionDefinition:封装事务的隔离级别,超时时间,是否为只读事务和事务的传
- 开门见山在IT圈里,每当我们谈论并发时,必定会说起在一台计算机上同时运行的一系列线程。如果这台电脑上有多个处理器或者是一个多核处理器,那么这
- jwt简介冒泡排序:(Bubble Sort)是一种简单的交换排序。之所以叫做冒泡排序,因为我们可以把每个元素当成一个小气泡,根据气泡大小,
- 添加注解效果事务演示注解我们经常会用到,或者在jdk源码中也会看到,例如: @Deprecated以及我们在spring或者spr
- Android 资源 id详解我们平时获取资源是通过 findViewById 方法进行的,比如我们常在onCreate方法中使用这样的语句
- 引言上一节讲面试中被问到分布式系统概念相关的,讲完了分布式系统的概念,优点缺点和 RPC 后,我以为这个问题就到此结束了,没想到成功给自己挖
- 一、代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强。加入一些非业务性代码,比如事务、日志、报警发邮件等
- 1.添加引用工具箱---右键---选择项--COM组件--Adobe PDF Reader2.使用方法OpenFileDialog open
- 最近在研究dubbo时,发现了JAVA的SPI特性。SPI的全名为Service Provider Interface,是JDK内置的一种服
- 什么是RecyclerView关于RecyclerView,是一个主要用于展示和回收View的有一个控件,在官用了一句话来概括Recycle