嵌套滚动实践:onInterceptTouchEvent与NestedScrolling【实用为准】
嵌套滚动:内外两层均可滚动,比如上半部分是一个有限的列表,下半部分是WebView,在内层上半部分展示到底的时候,外部父布局整体滚动内部View,将底部WevView拉起来,滚动到顶部之后再将滚动交给内部WebView,之后滚动的就是内部WebView,如下图:
实现:onInterceptTouchEvent或者NestedScroll
按照上下两部分构建父布局,父ViewGroup建议继承FrameLayout/RelativeLayout来实现,方便处理测量[无需复写]与布局,在计算出全部View高度后,可以计算最大父布局滚动距离:
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {var top = tvar bottom = bfor (i in 0 until childCount) {getChildAt(i).layout(l, top, r, bottom)top += getChildAt(i).measuredHeightbottom += getChildAt(i).measuredHeighttotalHeight += getChildAt(i).measuredHeight}maxScrollHeight = totalHeight - measuredHeight
}
上述交互有两种比较常用的方式,一种是onInterceptTouchEvent全局拦击Touch事件来实现拖动与Fling的处理,另一种是借助后期推出的NestedScroll框架来实现。先简单看下传统的onInterceptTouchEvent拦截的方式:核心的处理事两个操作,一个是拖动、一个是UP后的Fling,onInterceptTouchEvent首先要确定拦截的时机:判断有效拖动
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {when (event.actionMasked) {MotionEvent.ACTION_DOWN -> {mLastY = event.rawYmDownY = event.rawYmDownX = event.rawXmBeDraging = false}MotionEvent.ACTION_MOVE -> if (abs(event.rawY - mDownY) > ViewConfiguration.get(context).scaledTouchSlop) {mBeDraging = truereturn true} else {mLastY = event.rawY}else -> {}}return super.onInterceptTouchEvent(event)
}
一般而言垂直滚动超过某个TouchSlop就可以认为拖动有效,拖动开始,子View后续无法获取到Touch事件,其实大多数场景而言,父布局接管之后,没有必要再给子View分发事件,之后自行处理拖拽与Fling。
onInterceptTouchEvent方式处理拖拽与fling
处理拖拽与fling需要注意衔接,所以需要准备好GestureDetector,用于将来的fling,建议放在dispatchTouchEvent整体处理事件的消费
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {if (ev != null) {gestureDetector.onTouchEvent(ev)}if (ev?.action == MotionEvent.ACTION_DOWN)overScrollerNest.abortAnimation()if (ev?.action == MotionEvent.ACTION_MOVE && mBeDraging) {scrollInner((mLastY - ev.rawY).roundToInt())mLastY = ev.rawY}return super.dispatchTouchEvent(ev)
}
拖拽的控制方式:自己计算出可滚动的距离,可以利用View的canScrollVertically判断View是否能消费,从而决定留给哪个View
private fun scrollInner(dy: Int) {var pConsume: Int = 0var cConsume: Int = 0if (dy > 0) {if (scrollY in 1 until maxScrollHeight) {pConsume = dy.coerceAtMost(maxScrollHeight - scrollY)scrollBy(0, dy)cConsume = dy - pConsumeif (bottomView.canScrollVertically(cConsume) && cConsume != 0) {bottomView.scrollBy(0, cConsume)}} else if (scrollY == 0) {bottomView.scrollTo(0, 0)if (upView.canScrollVertically(dy)) {upView.scrollBy(0, dy)} else {if (canScrollVertically(dy)) {scrollBy(0, dy)}}} else if (scrollY >= maxScrollHeight) {scrollTo(0, maxScrollHeight)if (bottomView.canScrollVertically(dy)) {bottomView.scrollBy(0, dy)} else {overScrollerNest.abortAnimation()}}} else {if (scrollY in 1 until maxScrollHeight) {pConsume = Math.max(dy, -scrollY)scrollBy(0, pConsume)cConsume = dy - pConsumeif (bottomView.canScrollVertically(cConsume)) {bottomView.scrollBy(0, cConsume)}} else if (scrollY == maxScrollHeight) {if (bottomView.canScrollVertically(dy)) {bottomView.scrollBy(0, dy)} else {if (canScrollVertically(dy)) {scrollBy(0, dy)}}} else {if (upView.canScrollVertically(dy)) {upView.scrollBy(0, dy)}bottomView.scrollTo(0, 0)}}invalidate()}
拖拽结束后,fling跟上利用GestureDetector的onFling,直接让Scroller接上即可 overScroller = OverScroller(context),一般用OverScroller的体验好一些:
private GestureDetector gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float velocityX, float velocityY) {if (!(Math.abs(e1.getX() - e2.getX()) > mTouchSlop && Math.abs(velocityX) > Math.abs(velocityY))) {<!--衔接滚动-->overScroller.fling(0, 0, 0, (int) velocityY, 0, 0, -10 * ScreenUtil.getDisplayHeight(), 10 * ScreenUtil.getDisplayHeight());<!--必须触发一次-->postInvalidate();}return super.onFling(e1, e2, velocityX, velocityY);}
});
在computeScroll里从新计算应该滚动的距离,可以看到全局接管,并利用scrollBy自行控制滚动的偏移量是这种方案的核心
var mLastOverScrollerValue = 0override fun computeScroll() {super.computeScroll()if (overScrollerNest.computeScrollOffset()) {scrollInner(overScrollerNest.currY - mLastOverScrollerValue)mLastOverScrollerValue = overScrollerNest.currYinvalidate()}}
如此就可以利用onInterceptTouchEvent实现嵌套滚动,不涉及太多内部View【仅仅是获取了内部View的高度及判断是否可滚】,一切交给父布局即可。
利用NestedScrolling框架实现嵌套滑动
Android5.0推出了嵌套滑动机制NestedScrolling,让父View和子View在滑动时相互协调配合,为了向前兼容又抽离了NestedScrollingChild、NestedScrollingParent、NestedScrollingChildHelper、NestedScrollingParentHelper等支持类,不过在23年的场景下基本不需要使用这些辅助类了。NestedScrolling的核心是子View一直能收到Move事件,在自己处理之前先交给父View消费,父View处理完之后,再将余量还给子View,让子View自己处理,可以看出这套框架必须父子配合,也就是NestedScrollingChild、NestedScrollingParent是配套的。5.0之后View与ViewGroup本身就实现了NestedScrollingChild+NestedScrollingParent的框架,自定义布局的时候只需要定制与启用,也就是必须进行二次开发,目前Google提供的最好用的就是RecyclerView。有张图很清晰的描述NestedScrolling框架是如何工作的:
NestedScrolling只处理拖动[target无法改变],Fling交给Parent处理
在这个框架中,子View必须主动启动嵌套滑动、并且在Move的时候主动请求父ViewGroup进行处理,这样才能完成协同,并非简单的打开开关,所有的定制逻辑仍旧需要开发者自己处理,只是替代了onInterceptTouchEvent,提供了子View回传事件给父View的能力,不用父View主动拦截,也能获取接管子View事件的能力。
以开头描述的场景为例,如果上部分用ScrollView下部分用WebView,那么必须将两者都改造成NestedScrollingChild,也就是NestedScrollView与NestedWebView,NestedScrollView谷歌已经提供,NestedWebView目前没有,需要自己封装,可以看看如何配合实现一套嵌套滑动交互:
class NetScrollWebView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
) : WebView(context, attrs) {private val mTouchSlop = android.view.ViewConfiguration.get(context).scaledTouchSlopprivate val mScrollOffset = IntArray(2)private val mScrollConsumed = IntArray(2)init {<!--启动嵌套滑动-->isNestedScrollingEnabled = true}private var mLastY: Float = 0fprivate var dragIng: Boolean = falseoverride fun dispatchTouchEvent(ev: MotionEvent?): Boolean {when (ev?.action) {MotionEvent.ACTION_MOVE -> {if (abs(ev.rawY - mLastY) > mTouchSlop) {dragIng = true} else {super.dispatchTouchEvent(ev)}if (dragIng) {if (parent != null) {parent.requestDisallowInterceptTouchEvent(true)}<!--主动调用dispatchNestedPreScroll,请求父容器处理-->dispatchNestedPreScroll(0, (mLastY - ev.rawY).toInt(), mScrollConsumed, mScrollOffset)mLastY = ev.rawY}}MotionEvent.ACTION_DOWN -> {dragIng = falsesuper.dispatchTouchEvent(ev)<!--startNestedScroll启动嵌套滑动-->startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)mScrollConsumed[1] = 0mLastY = ev.rawY}MotionEvent.ACTION_UP -> stopNestedScroll()else -> super.dispatchTouchEvent(ev)}return true}// 强制自己不消费moveoverride fun onTouchEvent(ev: MotionEvent?): Boolean {if (dragIng || ev?.action == MotionEvent.ACTION_MOVE)return falsereturn super.onTouchEvent(ev)}}
- setNestedScrollingEnabled(true) ,后续的dispatch都依赖该开关
- 子View收到DOWN事件的时候启动startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL),【无论有没有NestedScrollingParent】
- 父布局其实这个时候也会响应,只有存在支持嵌套滑动的父布局,后续dispatchNestedPreScroll等函数才有意义才有意义
- 假设存在支持嵌套滑动的父布局,在MOVE的时候,调用dispatchNestedPreScroll让父布局处理
- 在MotionEvent.ACTION_UP的时候,stopNestedScroll ,由于WebView是ViewGroup,所以可以直接在dispatchTouchEvent处理,如果是View可以在onTouchEvent中处理
如此一个简单的NestedScrollingChild就完成了,但是只有这个并不能完成上述需求,还需要一个NestedScrollingParent来配合,其实这里大部分的功能跟上述onInterceptTouchEvent的实现的类似,只不过
class NestUpDownTwoPartsScrollView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0,defStyleRes: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {private val gestureDetector: GestureDetector =GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {override fun onFling(与onInterceptTouchEvent一致...})...<!--标志父布局支持垂直的嵌套滑动-->override fun onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int): Boolean {return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL}<!--被NestedScrollingChild回调-->override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray) {overScrollerNest.abortAnimation()scrollInner(dy)<!--完全给消费-->consumed[1] = dy}
<!--拦截子View们的fling--> override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {// 获取的fling速度有差异,原因不详return true}var mLastOverScrollerValue = 0<!--自己处理fling-->override fun computeScroll() {super.computeScroll()<!--自己处理fling-->if (overScrollerNest.computeScrollOffset()) {scrollInner(overScrollerNest.currY - mLastOverScrollerValue)mLastOverScrollerValue = overScrollerNest.currYinvalidate()}}private lateinit var overScrollerNest: OverScrolleroverride fun computeVerticalScrollRange(): Int {return totalHeight}private fun scrollInner(dy: Int) {... 与onInterceptTouchEvent一致}override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {if (ev != null) {gestureDetector.onTouchEvent(ev)}if (ev?.action == MotionEvent.ACTION_DOWN)overScrollerNest.abortAnimation()return super.dispatchTouchEvent(ev)}
}
父布局的操作如下
- onStartNestedScroll 返回true 启动
- 被子View调用onNestedPreScroll开始协同滑动
- onNestedPreFling接管Fling
- 利用GestureDetector+OverScroller自行处理Fling
可以看到,在这个框架下,可以比较灵活的接管拖动,不用自己拦截,而且消费多少,可以父子协商,关于Fling,可以处理成一致,而且有两个滚动布局衔接的时候,交给外部统一处理应该也是最合理的做法,防止两个View的Scroller不一致,而且嵌套滑动也无法处理target切换的问题。
NestedScrolling框架 使用注意点
- fling处理:尽量不使用内层GestureDetector来获取,因为内外侧获取MotionEvent不是统一的,所以内外层获取的fling初始速度可能不同,衔接易出问题,还是统一给外层自己做
- move处理拖拽:尽量使用rawY,因为MotionEvent获取的Y在嵌套滚动时候不如rawY直观,rawY始终是相对屏幕,而Y是相对自己View,在父View进行滚动的时候,target的Y几乎是不动的
强大的RecyclerView
RecyclerView适配一切,利用RecyclerView内嵌WebView也能实现上述效果:但需要主动控制内部可滚动Item。RecyclerView自身实现了onInterceptTouchEvent逻辑,理论上内部子View是无法获取到拦截之后的事件,只能依赖外部主动控制,否则WebView被拖到顶部就结束了,内部无法继续拖拽。但是RecyclerView本身实现了NestedScrollingChild3,可以看做是一个支持嵌套滑动的Child,在NestedScrolling框架中Move事件时一般会直接调用dispatchNestedPreScroll,之后dispatchNestedPreScroll会区分是否能启用嵌套滑动。因此除了借助 onInterceptTouchEvent逻辑,还可以借助dispatchNestedPreScroll来处理,一种很猥琐的做法:继承RecyclerView,复写dispatchNestedPreScroll,这个时候继承类先父类RecyclerView获取事件处理的优先权,在一定程度上看做实现了onInterceptTouchEvent的NestedScrollingChild,在复写的dispatchNestedPreScroll种处理子View的滚动。即可自身滚动,也能控制内部可滚动View的滚动,但很难做到那么通用。不过在做业务的时候,思路有时候胜过单纯的技术,尤其嵌套滑动,不需要过分追求通用型控件。
对于上述交互场景,只需在dispatchNestedPreScroll做如下处理:只需要主动接手内部子View的操控,外部的操控无需处理
override fun dispatchNestedPreScroll( dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?, type: Int): Boolean {var consumedSelf = false// 先让父布局处理,还是后处理?val parentScrollConsumed = mParentScrollConsumedval parentConsumed = super.dispatchNestedPreScroll( dx, dy, parentScrollConsumed, offsetInWindow, type)consumed?.let {consumed[1] += parentScrollConsumed[1]}<!--再交给自己已处理-->if (type == ViewCompat.TYPE_TOUCH) {<!--对于向上滚动,如果自身可是滚动就直接滚动自身,说明还没到顶部RecyclerView会自己处理,自己拦截过了无需外部干预,如果自身不能滚,就滚动内部的可滚动target-->if (!canScrollVertically(1)) {//外部自身的操控无需处理<!--fetchNestedChild是用来获取内部的可滚动View,这个看具体业务操作-->val remain = dy - (consumed?.get(1) ?: 0)if (remain > 0) {// 已经到顶了if (!canScrollVertically(1)) {val target = fetchBottomNestedScrollChild()target?.apply {this.scrollBy(0, remain)consumed?.let {it[1] += remain}consumedSelf = true}}}// down 其实还是自己控制,而不是底层控制if (remain < 0) {val target = fetchBottomNestedScrollChild()target?.apply {if (this.canScrollVertically(-1)) {this.scrollBy(0, remain)// 消耗完,不给底层机会consumed?.let {it[1] += remain}consumedSelf = true}}}}return consumedSelf || parentConsumed
}
拖拽是比较容易处理的,比较棘手的是对于fling的处理,fling是一次性的,如果Recycleview继承类dispatchNestedPreFling自己处理了fling后,父布局就获取不到,衔接就比较麻烦
override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {fling(velocityY)return true}
如果Recycleview自身通过OverScroller处理完毕后,还有盈余,就需要将盈余给外部,先处理内部,还是先处理外部都是可选的,看用户自己
override fun computeScroll() {if (overScroller.computeScrollOffset()) {val current = overScroller.currYval dy = current - mCurrentFlingmCurrentFling = currentval target = fetchBottomNestedScrollChild()if (dy > 0) {if (canScrollVertically(1)) {scrollBy(0, dy)} else {if (target?.canScrollVertically(1) == true) {target.scrollBy(0, dy)} else {if (!overScroller.isFinished) {overScroller.abortAnimation()// fling 先内部,给上面接管一部分startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)dispatchNestedFling(0f, overScroller.currVelocity, false)stopNestedScroll()}
处理方式就是内部不可fling之后,主动通过startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)与 dispatchNestedFling再次交给父布局。
总结
流畅交互全靠微调
相关文章:
嵌套滚动实践:onInterceptTouchEvent与NestedScrolling【实用为准】
嵌套滚动:内外两层均可滚动,比如上半部分是一个有限的列表,下半部分是WebView,在内层上半部分展示到底的时候,外部父布局整体滚动内部View,将底部WevView拉起来,滚动到顶部之后再将滚动交给内部…...
Redis入门 - 5种基本数据类型
原文首更地址,阅读效果更佳! Redis入门 - 5种基本数据类型 | CoderMast编程桅杆https://www.codermast.com/database/redis/five-base-datatype.html 说明 在我们平常的业务中基本只会使用到Redis的基本数据类型(String、List、Hash、Set、…...
mybatis-plus用法(一)
MyBatis-plus 是一款 Mybatis 增强工具,用于简化开发,提高效率。下文使用缩写 mp来简化表示 MyBatis-plus,本文主要介绍 mp 整合 Spring Boot 的使用。 (5条消息) mybatis-plus用法(二)_渣娃工程师的博客-CSDN博客 1…...
源码安装包管理
1. 源码包基本概述 在linux环境下面安装源码包是比较常见的, 早期运维管理工作中,大部分软件都是通过源码安装的。那么安装一个源码包,是需要我们自己把源代码编译成二进制的可执行文件。 源码包的编译用到了linux系统里的编译器,通常源码包…...
Vue|获取表单数据
在Vue中获取表单数据有多种方式,具体取决于你使用的是哪种表单元素和你的需求。 1. 单个表单元素: 如果你只需要获取单个表单元素的值,可以使用v-model指令将表单元素的值绑定到Vue实例的一个属性上。例如: <input type&quo…...
微信小程序入门学习02-TDesign中的自定义组件
目录 1 显示文本2 自定义组件3 变量定义4 值绑定总结 我们上一篇讲解了TDesign模板的基本用法,如何开始阅读模板。本篇我们讲解一下自定义组件的用法。 1 显示文本 官方模板在顶部除了显示图片外,还显示了一段文字介绍。文字是嵌套在容器组件里…...
【linux kernel】linux media子系统分析之media控制器设备
文章目录 一、抽象媒体设备模型二、媒体设备三、Entity四、Interfaces五、Pad六、Link七、Media图遍历八、使用计数和电源处理九、link设置十、Pipeline和Media流十一、链接验证十二、媒体控制器设备的分配器API 本文基于linux内核 4.19.4,抽象媒体设备模型框架的相…...
Scala--03
第6章 面向对象 Scala 的面向对象思想和Java 的面向对象思想和概念是一致的。 Scala 中语法和 Java 不同,补充了更多的功能。 6.1类和对象详解 6.1.1组成结构 构造函数: 在创建对象的时候给属性赋值 成员变量: 成员方法(函数) 局部变量 代码块 6.1.2构造器…...
【MongoDB】--MongoDB高级功能
目录 一、前言二、聚合管道aggregate1、示例说明2、具体代码实现一、前言 这里主要记录mongodb一些高级功能使用,如聚合。 二、聚合管道aggregate 聚合操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果,主要用于处理数据(诸如统计平均值,…...
C# new与malloc
目录 C# new与malloc C# new与malloc的区别 C# new关键字底层做的操作 C# new与malloc new关键字: new关键字在C#中用于实例化对象,并为其分配内存。它是面向对象编程的基本操作之一。使用new关键字可以在托管堆上分配内存,同时调用对象的构…...
微软MFC技术简明介绍
我是荔园微风,作为一名在IT界整整25年的老兵,今天来看一下微软MFC技术简明介绍 Visual C 与 MFC 微软公司于1992年上半年推出了C/C 7.0 产品时初次向世人介绍了MFC 1.0,这个产品包含了20,000行C原始代码,60个以上的Windows相关类…...
汽车电子Autosar之车载以太网
前言 近些年来,随着为了让汽车更加安全、智能、环保等,一系列的高级辅助驾驶功能喷涌而出。未来满足这些需求,就对传统的电子电器架构带来了严峻的考验,需要越来越多的电子部件参与信息交互,导致对网络传输速率&#x…...
MSP430_C语言例程注释详
本章选择了一些简单的C语言程序例题,这些程序的结构简单,编程技巧不多,题目虽然 简单,但是非常适合入门单片机的学习者学习MSP430单片机的C 语言编程。 如下列出了C语言例题运行的MSP430F149实验板硬件资源环境,熟悉…...
Vb+access库存管理系统(论文+开题报告+源代码+目录)
库存信息管理系统的基本问题1.1 库存信息管理系统的简介 本系统是为了提高腾达公司自动化办公的水平、经过详细的调查分析初步制定了腾达公司库存信息管理系统。基于WINDOWS 98 平台,使用Microsoft Access97, 在Visual Basic 6.0编程环境下开发的库存信息管理系统。该系统采用…...
Java 数组
在 Java 语言中,数组是一种基本的数据结构,可以存储一组相同类型的数据。本篇技术博客将详细介绍 Java 语言中的数组,包括一维数组和多维数组,以及数组的使用方法和注意事项。 一维数组 一维数组是指只有一行的数组,…...
CSDN 编程竞赛五十八期题解
竞赛总览 CSDN 编程竞赛五十八期:比赛详情 (csdn.net) 竞赛题解 题目1、打家劫舍 有一个小偷计划偷窃沿街的房屋,每间房内都藏有一定的现金,影响偷窃行为的唯一制约因素就是相邻的房屋装有相互连通的防盗系统。如果两间相邻的房屋在同一晚…...
Unity入门6——光源组件
一、参数面板 二、参数介绍 Type:光源类型 Spot:聚光灯 Range:发光距离Spot Angle:光锥角度Directional:方向光Point:点光源Area(Baked Only):面光源 仅烘焙。预先算好&…...
C语言之动态内存分配(1)
目录 本章重点 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 几个经典的笔试题 柔性数组 动态内存管理—自己维护自己的内存空间的大小 首先我们申请一个变量,再申请一个数组 这是我们目前知道的向内存申请…...
AIGC新时代,注意政策走向,产业方向,拥抱可信AI。需要了解基本理论,基础模型,前沿进展,产品应用,以及小小的项目复现
AIGC(AI-Generated Content,AI生成内容)是指基于生成对抗网络(GAN)、大型预训练模型等人工智能技术的方法,通过对已有数据进行学习和模式识别,以适当的泛化能力生成相关内容的技术。类似的概念还…...
如何白嫖一年CSDN会员?618活动!亲测有效!!!
活动详情 CSDN会员免费送一年,仅剩3天! 下载权益延长一年! 一年一次的机会,错过了就要再等明年! 博主已经领取到了! 会员权益 1、修改专属域名,别人都是https://blog.csdn.net/qq_xxxxxxxx&a…...
微服务: 00-rabbitmq出现的异常以及解决方案
目录 前言: 问题概述: 1. rabbitmq初始安装配置异常 -> 1.1 rabbitmq报您与此网站连接不是私密连接 --->1.1.1 上述问题解决方案 ---> 1.1.2 依次执行下面代码 -> 1.2 解决用户的No access情况 -> 1.2.1 使用设置的账号密码进行登录 -> 1.2.2 点击 Ad…...
Vue3与Vue2比较
Vue.js 3相对于Vue.js 2带来了一些重大变化,其中包括一些语法变化。 下面是Vue.js 2和Vue.js 3的一些语法差异比较: 一、语法差异比较 1.组件的注册方式不同 在Vue.js 2中,我们使用Vue.component()或者Vue.extend()方式创建一个组件。但是…...
如何对待工作中的失误?
在日复一日的工作中,我们免不了会产生一些失误,会因此感到沮丧和失望。但如何正确地对待和处理这些失误才是最重要的,它直接影响到我们的工作表现和个人成长。一起来谈谈作为职场人的你时如何处理工作中的失误的吧! 一、在面对失…...
使用css3如何实现一个文字打印效果
前言 在很多网站首页介绍页里,为了吸引用户,暂留更长时间,使用了一些css3动画的 示例效果 文字打印.gif 实现这个动画原理 想要实现这个动画,改变元素的宽度,结合动画css3关键帧实现 具体代码如下所示 <!DOCTYPE html> <html lang"en"><head><m…...
【雕爷学编程】Arduino动手做(115)---HB100多普勒雷达模块
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…...
深度学习笔记之Transformer(一)注意力机制基本介绍
深度学习笔记之Transformer——注意力机制基本介绍 引言回顾: Seq2seq \text{Seq2seq} Seq2seq模型中的注意力机制注意力机制的简单描述注意力机制的机器学习范例: Nadaraya-Watson \text{Nadaraya-Watson} Nadaraya-Watson核回归 Nadaraya-Watson \text…...
基于SpringBoot的SSM整合案例 -- SpringBoot快速入门保姆级教程(四)
文章目录 前言1.设计创建数据库表tbl_book2.创建新的SpringBoot模块,勾选相关依赖3. 添加SpringBoot创建项目时没有提供的相关坐标4.根据数据库表创建实体类Book5.编写dao层操作BookDao6.编写Service服务层接口BookService7.编写服务层实现类BookServiceImpl8.编写B…...
占据80%中国企业出海市场,亚马逊云科技如何为出海客户提供更多资源和附加值
亚马逊云科技就可以做到,作为占据80%中国企业出海市场的亚马逊云科技,其覆盖全球的业务体系,从亚马逊海外购、亚马逊全球开店、亚马逊智能硬件与服务,Amazon Alexa,Amazon Music都是属于亚马逊云科技“梦之队”的一员。…...
系统架构设计师笔记第11期:信息安全的抗攻击技术
拒绝服务攻击 拒绝服务攻击(Denial of Service,DoS)是一种旨在使目标系统无法提供正常服务的攻击方式。攻击者通过向目标系统发送大量的请求或占用系统资源,超过系统的承载能力,导致系统过载或崩溃,从而使…...
TLD7002学习笔记(二)-使用S32K144驱动TLD7002
文章目录 1. 前言2. 评估板简介3. 官方驱动3.1 官网驱动的介绍3.2 官方驱动的移植3.3 官方驱动的使用 4. 参考资料 1. 前言 本篇文章是TLD7002学习笔记的第二篇,主要是介绍如何使用S32K144驱动TLD7002-16ES。为此,笔者做了一套基于TLD7002-16ES的评估板…...
深圳大公司/百度热搜关键词排名优化
倒数60秒价格走势 可是然而但是,别人家都是怎么拍中的?答:不按套路出牌这次你就中了。 那么即使是这样,还有没有“套路”可循?答:肯定有的。 相信很多人都读过国拍官网的《网上投标拍卖操作流程》ÿ…...
专业做网站开发费用/怎么卸载windows优化大师
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼一股令楼主都战栗的气息压塌了苍穹,本屌丝来了!本屌深邃的双眼中有无尽日月星辰,举手投足间竟有大道在共鸣。只见本屌动了,一只古朴的大手横跨无数楼层,直压楼主而来。2楼…...
富阳网站/泉州百度seo
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域 说明: 关于闭包,即函数定义和函数表达…...
淘宝 做网站空间 条件/牛推网
接上一节,增加数据库身份认证 1、修改Config配置文件auth-enabled为true 2、然后重新载入最新的config配置文件打开数据库 3、验证身份认证功能是否已打开 说明身份认证功能已打开 4、创建admin管理员用户 CREATE USER admin WITH PASSWORD sa_123 WITH ALL PRIVILE…...
新版lnmp安装wordpress/seo搜索引擎优化怎么做
拓扑: 加密点和通信点 加密点10.1.1.1---10.1.1.2,通信点,1.1.1.1-2.2.2.2 说明:看这篇文章的前提是 ,你已经知道了怎么样申请证书。已经初步了解了证书的基本原理和一些域名的知识。这些细节,需要的可以百…...
教育网站建设的素材/怎样进行seo推广
所有题目均有五种语言实现。C实现目录、C++ 实现目录、Python实现目录、Java实现目录、JavaScript实现目录...