当前位置: 首页 > news >正文

flutter学习-day12-可滚动组件和监听

📚 目录

  1. 简介
  2. 可滚动组件
    1. SingleChildScrollView
    2. ListView
      1. separated分割线
      2. 无限加载列表
      3. 带标题列表
  3. 滚动监听和控制
    1. ScrollController滚动监听
    2. NotificationListener滚动监听
  4. AnimatedList动画列表
  5. 滚动网格布局GridView
    1. 横轴子元素为固定数量
    2. 横轴子元素为固定最大长度
    3. 动态创建
  6. PageView页面切换和缓存
    1. PageState缓存
  7. TabBarView
  8. CustomScrollView和Slivers
    1. 常用的Slivers

本文学习和引用自《Flutter实战·第二版》:作者:杜文

1. 简介

通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView。

Flutter 中的可滚动组件主要由三个角色组成:

  • Scrollable :用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport。
方法描述
axisDirection-滚动方向
physicsClampingScrollPhysics、BouncingScrollPhysics决定可滚动组件如何响应用户操作
controller-控制滚动位置和监听滚动事件
viewportBuilder-当用户滑动时,Scrollable 会调用此回调构建新的 Viewport,同时传递一个 ViewportOffset 类型的 offset 参数,该参数描述 Viewport 应该显示那一部分内容
  • Viewport:显示的视窗,即列表的可视区域。
方法描述
axisDirection-滚动方向
offset-用户的滚动偏移
cacheExtent-预渲染区域
CacheExtentStyle-用于配合解释cacheExtent的含义,也可以为主轴长度的乘数
slivers-需要显示的 Sliver 列表
  • Sliver:视窗里显示的元素,对子组件进行构建和布局。

如果要给可滚动组件添加滚动条,只需将Scrollbar作为可滚动组件的任意一个父级组件即可

2. 可滚动组件

本节讲一下SingleChildScrollView和ListView。

2-1 SingleChildScrollView

SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件。通常SingleChildScrollView只应在期望的内容不会超过屏幕太多时使用,因为不支持基于 Sliver 的延迟加载模型,可能性能差。

方法描述
scrollDirection-滚动方向
reverse-
padding-内边距
primary-是否使用 widget 树中默认的PrimaryScrollControlle
physics-决定可滚动组件如何响应用户操作
controller-控制器
child-子组件

竖向排列的字母表例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {String alphabet = 'ABCDEFGHIJKMLNOPKRSTUVWSYZ';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: SingleChildScrollView(padding: const EdgeInsets.all(16.0),child: Center(child: Column(children: alphabet.split('').map((e) => Text(e,textScaleFactor: 2.0,)).toList(),)),),));}
}

2-2. ListView

ListView是最常用的可滚动组件之一,内部组合了 Scrollable、Viewport 和 Sliver。它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。它有一个children参数,它接受一个Widget列表。这种方式适合只有少量的子组件数量已知且比较少的情况,反之则应该使用ListView.builder 按需动态构建列表项。

方法描述
itemExtent-子组件长度,如果指定了该值,就不用动态计算listview高度,性能更好
prototypeItem-指定一个列表项,可滚动组件会在 layout 时计算一次它延主轴方向的长度,和itemExtent互斥
shrinkWrapfalse是否根据子组件的总长度来设置ListView的长度
addRepaintBoundaries-是否将列表项(子组件)包裹在RepaintBoundary组件中,看list复杂情况设置
  • 数量固定的情况:
ListView(shrinkWrap: true, padding: const EdgeInsets.all(16.0),children: <Widget>[const Text('a'),const Text('b'),const Text('c'),const Text('d'),],
);
  • 数量不固定的情况:
ListView.builder(itemCount: 100,// 强制高度为50.0itemExtent: 50.0,itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));}
);

2-2-1. separated分割线

ListView.separated可以在生成的列表项之间添加一个分割组件,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割组件生成器。

  • 奇数行添加一条红色下划线,偶数行添加一条绿色下划线:
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {Widget divider1 = const Divider(color: Colors.red);Widget divider2 = const Divider(color: Colors.green);Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: 100,// 列表项构造器itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));},// 分割器构造器separatorBuilder: (BuildContext context, int index) {return index % 2 == 0 ? divider1 : divider2;},));}
}

2-2-2. 无限加载列表

在实际开发中,我们经常需要实现一个无限加载列表,即当列表滚动到底部时,再向服务器请求数据,并添加到列表,例子如下:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {static const loadingTag = "##loading##"; //表尾标记var words = <String>[loadingTag];void initState() {super.initState();_retrieveData();}// 加载数据void _retrieveData() {Future.delayed(const Duration(seconds: 2)).then((e) {setState(() {//重新构建列表words.insertAll(words.length - 1,//每次生成20个单词generateWordPairs().take(20).map((e) => e.asPascalCase).toList(),);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: words.length,itemBuilder: (context, index) {// 如果到了表尾if (words[index] == loadingTag) {// 不足100条,继续获取数据if (words.length - 1 < 100) {// 获取数据_retrieveData();// 加载时显示loadingreturn Container(padding: const EdgeInsets.all(16.0),alignment: Alignment.center,child: const SizedBox(width: 24.0,height: 24.0,child: CircularProgressIndicator(strokeWidth: 2.0),),);} else {// 已经加载了100条数据,不再获取数据return Container(alignment: Alignment.center,padding: const EdgeInsets.all(16.0),child: const Text("没有更多了",style: TextStyle(color: Colors.grey),),);}}// 显示单词列表项return ListTile(title: Text(words[index]));},separatorBuilder: (context, index) => const Divider(height: .0),));}
}

2-2-3. 带标题列表

Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Column(children: [// 标题const ListTile(title: Text('标题')),// 用Expanded 占满剩余空间Expanded(child: ListView.builder(itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'),);}),)],));}

3. 滚动监听和控制

可以用ScrollController来控制可滚动组件的滚动位置。而,可滚动组件在滚动时会发送ScrollNotification类型的通知,ScrollBar正是通过监听滚动通知来实现的。

3-1. ScrollController滚动监听

ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件。如下例子:

  • 滚动到1000的时候,出现回到顶部的按钮,点击即可回到顶部
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 监听控制器ScrollController myController = ScrollController();/// 是否显示回到顶部按钮bool toTop = false;void initState() {super.initState();/// 开启监听myController.addListener(() {if (myController.offset < 1000 && toTop) {setState(() {toTop = false;});} else if (myController.offset >= 1000 && toTop == false) {setState(() {toTop = true;});}});}void dispose() {/// 注销监听myController.dispose();super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: ListView.builder(/// 固定列数itemCount: 100,/// 固定列高itemExtent: 50.0,controller: myController,/// 渲染行itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'));},)),/// 返回顶部按钮floatingActionButton: !toTop? null: FloatingActionButton(child: const Icon(Icons.arrow_upward),onPressed: () {/// 动画返回myController.animateTo(0.0,duration: const Duration(microseconds: 200),curve: Curves.ease);},),);}
}

3-2. NotificationListener滚动监听

和ScrollController不同,NotificationListener可以在可滚动组件到widget树根之间任意位置监听,而ScrollController只能和具体的可滚动组件关联后才可以。并且,收到滚动事件时,NotificationListener通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。如下例子:

  • 中间有个文字会显示滚动的进度是多少
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 进度文案String myProgress = '0%';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: NotificationListener(onNotification: (ScrollNotification  notification) {double progress = notification.metrics.pixels / notification.metrics.maxScrollExtent;setState(() {myProgress = '${(progress * 100).toInt()}%';});return false;},child: Stack(alignment: Alignment.center,children: [ListView.builder(itemCount: 100,itemExtent: 50.0,itemBuilder: (context, index) => ListTile(title: Text('第$index行'),),),CircleAvatar(radius: 30.0,backgroundColor: Colors.black12,child: Text(myProgress))],),));}
}

4. AnimatedList动画列表

AnimatedList 和 ListView 的功能大体相似,不同的是, AnimatedList 可以在列表中插入或删除节点时执行一个动画,在需要添加或删除列表项的场景中会提高用户体验。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 数据列表var dataList = <String>[];/// 初始个数int counter = 6;/// Keyfinal myKey = GlobalKey<AnimatedListState>();void initState() {super.initState();/// 初始化数据for (var i = 0; i < counter; i++) {dataList.add('标题:${i + 1}');}}Widget buildItem(context, index) {String str = dataList[index];return ListTile(key: ValueKey(str),title: Text(str),trailing: IconButton(icon: const Icon(Icons.delete),onPressed: () {/// 删除的逻辑和动画setState(() {myKey.currentState!.removeItem(index, (context, animation) {var item = buildItem(context, index);dataList.removeAt(index);return FadeTransition(opacity: CurvedAnimation(parent: animation, curve: const Interval(0.5, 1.0)),child: SizeTransition(sizeFactor: animation,axisAlignment: 0.0,child: item,),);}, duration: const Duration(milliseconds: 200));});},),);}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Stack(alignment: Alignment.center,children: [AnimatedList(key: myKey,initialItemCount: dataList.length,itemBuilder: (context, index, animation) {return FadeTransition(opacity: animation, child: buildItem(context, index));},),Positioned(left: 0,right: 0,bottom: 30.0,child: FloatingActionButton(/// 添加项onPressed: () {dataList.add('标题:${++counter}');myKey.currentState!.insertItem(dataList.length - 1);},child: const Icon(Icons.add),),)],));}
}

5. 滚动网格布局GridView

GridView是ListView的升级版,可以构建二维网格列表,可以指定子组件的布局方式,如网格布局、列表布局等。他的参数和ListView是一致的,唯一区别是多了个gridDelegate参数,控制GridView子组件的排列。它提供了SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent两个子类。

5-1. 横轴子元素为固定数量

使用SliverGridDelegateWithFixedCrossAxisCount,可以实现一个横轴为固定数量子元素的layout布局。子元素的大小(最大显示空间)是通过crossAxisCount和childAspectRatio两个参数共同决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 横轴子元素的数量crossAxisCount: 3,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0),/// 元素列表children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)
/// 写法二
GridView.count( crossAxisCount: 3,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-2. 横轴子元素为固定最大长度

使用SliverGridDelegateWithMaxCrossAxisExtent,可以实现一个横轴子元素为固定最大长度的layout布局,子元素的大小(最大显示空间)是通过maxCrossAxisExtent参数决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(/// 子元素在横轴上的最大长度maxCrossAxisExtent: 100.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,),children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)/// 写法二
GridView.extent(maxCrossAxisExtent: 120.0,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-3. 动态创建

当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// Icon列表List<IconData> myIcons = [];void initState() {super.initState();/// 初始化数据handleSyncAddIcon();}/// 模拟异步获取数据void handleSyncAddIcon() {Future.delayed(const Duration(milliseconds: 2000)).then((e) {setState(() {myIcons.addAll([Icons.ac_unit,Icons.airport_shuttle,Icons.all_inclusive,Icons.beach_access,Icons.cake,Icons.free_breakfast,]);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 每行三列crossAxisCount: 3,/// 显示区域宽高相等childAspectRatio: 1.0,),itemCount: myIcons.length,itemBuilder: (context, index) {/// 如果显示到最后一个 并且Icon总数小于200时 继续获取数据if (index == myIcons.length - 1 && myIcons.length < 200) {handleSyncAddIcon();}return Icon(myIcons[index]);},));}
}

6. PageView页面切换和缓存

如果要实现页面切换和 Tab 布局,Tab 换页效果、图片轮动以及抖音上下滑页切换视频功能等等,我们可以使用 PageView 组件。如下全屏切换的例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> {Widget build(BuildContext context) {debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

6-1. PageState缓存

只需要让 PageState 混入这个 AutomaticKeepAliveClientMixin ,简单改造就可以实现缓存。

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

7. TabBarView

abBarView 封装了 PageView,而abController 用于监听和控制 TabBarView 的页面切换,通常和 TabBar 联动。如果没有指定,则会在组件树中向上查找并使用最近的一个 DefaultTabController。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key, required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("${widget.text}", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];List tabs = ["新闻", "历史", "图片"];void initState() {super.initState();for (int i = 0; i < tabs.length; ++i) {children.add(PageItem(text: '${tabs[i]}'));}}Widget build(BuildContext context) {return DefaultTabController(length: children.length,child: Scaffold(appBar: AppBar(title: const Text("App Name"),bottom: TabBar(tabs: tabs.map((e) => Tab(text: e)).toList(),),),body: TabBarView(/// tab子页面children: children,),),);}
}

8. CustomScrollView和Slivers

CustomScrollView的 slivers 参数接受一个 Sliver 数组,这样就可以在一个页面中,同时包含多个可滚动组件,且使它们的滑动效果能统一起来。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {var listView = SliverFixedExtentList(itemExtent: 56,delegate: SliverChildBuilderDelegate((_, index) => ListTile(title: Text('$index')),childCount: 10,));Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Center(child: CustomScrollView(slivers: [listView,listView,],),));}
}

8-1. 常用的Slivers

  • 可滚动组件对应的Sliver
名称功能对应组件
SliverList列表ListView
SliverFixedExtentList高度固定的列表ListView,指定itemExtent后
SliverAnimatedList添加/删除列表项可以执行动画AnimatedList
SliverGrid网格GridView
SliverPrototypeExtentList根据原型生成高度固定的列表ListView,指定prototypeItem后
SliverFillViewport包含多个子组件,每个都可以填满屏幕PageView
  • 子组件必须是Sliver
名称对应RenderBox容器
SliverPaddingPadding
SliverVisibility、SliverOpacityVisibility、Opacity
SliverFadeTransitionFadeTransition
SliverLayoutBuilderLayoutBuilder
  • 其他常用的Sliver
名称功能
SliverAppBar对应 AppBar,主要是为了在 CustomScrollView 中使用
SliverToBoxAdapter一个适配器,可以将 RenderBox 适配为 Sliver
SliverPersistentHeader滑动到顶部时可以固定住

本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

  • 手把手教你搭建规范的团队vue项目,包含commitlint,eslint,prettier,husky,commitizen等等
  • Web Woeker和Shared Worker的使用以及案例
  • Vue2全家桶+Element搭建的PC端在线音乐网站
  • vue3+element-plus配置cdn
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超详细!Vue的九种通信方式
  • 超详细!Vuex手把手教程
  • 使用nvm管理node.js版本以及更换npm淘宝镜像源
  • vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
  • 超详细!Vue-Router手把手教程

个人主页

  • CSDN
  • GitHub
  • 简书
  • 博客园
  • 掘金

相关文章:

flutter学习-day12-可滚动组件和监听

&#x1f4da; 目录 简介可滚动组件 SingleChildScrollViewListView separated分割线无限加载列表带标题列表 滚动监听和控制 ScrollController滚动监听NotificationListener滚动监听 AnimatedList动画列表滚动网格布局GridView 横轴子元素为固定数量横轴子元素为固定最大长度…...

LeetCode:967连续查相同的数字(DFS)

题目 返回所有长度为 n 且满足其每两个连续位上的数字之间的差的绝对值为 k 的 非负整数 。 请注意&#xff0c;除了 数字 0 本身之外&#xff0c;答案中的每个数字都 不能 有前导零。例如&#xff0c;01 有一个前导零&#xff0c;所以是无效的&#xff1b;但 0 是有效的。 …...

深入剖析NPM: Node包管理器的介绍和使用指南

导言&#xff1a;NPM&#xff08;Node Package Manager&#xff09;是JavaScript世界中最受欢迎的包管理器之一。它的出现大大简化了JavaScript开发过程中的依赖管理和模块化。本文将向您介绍NPM的基本概念、功能和常见用法&#xff0c;并为您提供一份详尽的NPM使用指南。 一、…...

AI视频-stable-video-diffusio介绍

介绍 stbilityai/stable-video-diffusion-img2vid-xt模型&#xff0c;由Stability AI开发和训练的基于散度的图像到视频生成模型。该模型可以接受一张静态图像作为条件,并生成出一个短视频。 该模型通过在SVD Image-to-Video [14帧]的基础上进行微调而来,可以生成576x1024分辨…...

day01-报表技术POI

前言 报表[forms for reporting to the higher organizations]&#xff0c;就是向上级报告情况的表格。简单的说&#xff1a;报表就是用表格、图表等格式来动态显示数据&#xff0c;可以用公式表示为&#xff1a;“报表 多样的格式 动态的数据”。 1、开发环境搭建 功能说…...

如何预防最新的.locked、.locked1勒索病毒感染您的计算机?

尊敬的读者&#xff1a; 近期&#xff0c;网络安全领域迎来一股新潮——.locked、.locked1勒索病毒的威胁&#xff0c;其先进的加密技术令人生畏。本文将深入剖析.locked、.locked1勒索病毒的阴谋&#xff0c;提供特色数据恢复策略&#xff0c;并揭示锁定恶劣行径的先锋预防手…...

实现两张图片的接缝线拼接

使用ORB算法检测特征点&#xff0c;并通过BFMatcher进行特征点匹配。然后&#xff0c;根据Lowes ratio test选择好的匹配点&#xff0c;并使用findHomography计算单应性矩阵。最后&#xff0c;使用warpPerspective将图像进行透视变换&#xff0c;然后将第二张图像粘贴到变换后的…...

基于JNI 实现 嵌套 List 类型参数解析

基于JNI 实现 嵌套 List 类型参数解析 背景分析解决 背景 在前面两篇文章中&#xff0c;我们总结了Java 调用 C/C SDK 的几种方案&#xff0c;分享了JNI在实践过程中的一些踩坑点&#xff0c;而在这篇文章将继续分享针对Java List类型及其嵌套类型&#xff0c;我们的JNI如何接…...

探索灵活性与可维护性的利器:策略(Strategy)模式详解

目录 ​编辑 1. 策略模式概述&#xff1a; 2. 主要角色&#xff1a; 3. 实例场景&#xff1a; 4. 具体实现步骤&#xff1a; 步骤一&#xff1a;定义策略接口 5. 使用策略模式的客户端代码&#xff1a; 总结&#xff1a; 我的其他博客 1. 策略模式概述&#xff1a; 策…...

压缩包文件暴力破解 -Server2005(解析)

任务五十一: 压缩包文件暴力破解 任务环境说明:Server2005 1. 通过本地PC中渗透测试平台Kali使用Nmap扫描目标靶机服务版本信息,将 Telnet 版本信息字符串 作为 Flag 提交; flag:Microsoft Windows XP telnetd 2. 通过本地PC中渗透测试平台Kali对服务器场景Windows进行渗透测…...

mars3d加载arcgis发布的服务,⽀持4523坐标

问题 1.从这个服务地址加载&#xff0c;具体在哪⾥去转坐标呢&#xff1f; 加个 usePreCachedTilesIfAvailable&#xff1a;false 参数即可 坐标系为4490的arcgis影像服务图层&#xff0c;配置后瓦片加载不出来&#xff0c;没报错 甚至可以跳转 没有看出问题&#xff0c;或者测…...

『K8S 入门』二:深入 Pod

『K8S 入门』二&#xff1a;深入 Pod 一、基础命令 获取所有 Pod kubectl get pods2. 获取 deploy kubectl get deploy3. 删除 deploy&#xff0c;这时候相应的 pod 就没了 kubectl delete deploy nginx4. 虽然删掉了 Pod&#xff0c;但是这是时候还有 service&#xff0c…...

十七、如何将MapReduce程序提交到YARN运行

1、启动某个节点的某一个用户 hadoopnode1:~$ jps 13025 Jps hadoopnode1:~$ yarn --daemon start resourcemanager hadoopnode1:~$ jps 13170 ResourceManager 13253 Jps hadoopnode1:~$ yarn --daemon start nodemanager hadoopnode1:~$ jps 13170 ResourceManager 15062 Jp…...

华为云CodeArts Deploy常见问答汇总

1.【Deploy】部署java项目&#xff0c;为什么通过springboot启动步骤启动失败了&#xff1f; 答&#xff1a;用户所部署的jar包源码并不是springboot框架&#xff0c;所以无法用springboot启动步骤启动&#xff0c;该步骤并不等同于java -jar 命令&#xff0c;需要使用shell脚…...

前后端交互—开发一个完整的服务器

代码下载 初始化 新建 apiServer 文件夹作为项目根目录&#xff0c;并在项目根目录中运行如下的命令&#xff0c;初始化包管理配置文件: npm init -y运行如下的命令&#xff0c;安装 express、cors: npm i express cors在项目根目录中新建 app.js 作为整个项目的入口文件&a…...

前端框架的虚拟DOM(Virtual DOM)

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...

什么是http状态码?

什么是http状态码&#xff1f; 当浏览者访问一个网页时&#xff0c;浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前&#xff0c;此网页所在的服务器会返回一个包含 HTTP 状态码的信息头&#xff08;server header&#xff09;用以响应浏览器的请求。 ht…...

linux/CentOS 7安装Nginx

Nginx 是 C语言 开发&#xff0c;建议在 Linux 上运行&#xff0c;当然&#xff0c;也可以安装 Windows 版本&#xff0c;本篇则使用 CentOS 7 作为安装环境。 Nginx一般使用非root账号安装&#xff0c;如果还没有非root账号&#xff0c;先创建账号 创建账号 创建组&#xf…...

软件工程期末复习+数据仓库ETL

一、软件工程 请用基本路径测试方法为下列程序设计测试用例&#xff0c;并写明中间过程&#xff1a; 第1步&#xff1a;画出流程图 1.菱形用于条件判断。用在有分支的地方。 2.矩形表示一个基本操作。 3.圆形是连接点 第2步&#xff1a;计算程序环路复杂性 流图G的环路复杂…...

学习C语言——体会计算机中的0和1

/* 把hello隐写入一个整型数组,这个小程序可以考察是否清楚数据在内存中存储的具体细节。 具体的说&#xff0c;int类型在小端机器上的存储方式是高位在高地址&#xff0c;低位在低地址&#xff0c;从视觉习惯上和我们的日常书写习惯相反&#xff1b; char类型占用…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...