RUST语言的初印象-从一个模拟登陆谈起-slint+reqwest+aes
本文就一个做了三四天的小程序讲第一次学用RUST的感受,内附代码。
了角语言
从一些渠道听说了R,这个字母挺魔性,那个文章说C++和R的团体已经上升到了宗教崇拜的高度,然后,我觉得必 有过人之处,大约10年没碰C++,只知皮毛。于是想要去学一下R,这样简写是为了方便凑合看。粗粗一打听,这语言是系统的,平台通吃,android,arm,x86.苹果,安装起来也十分方便,curl一段代码就行。除了win下要用VStuty。正好我上次python,exe化的进候安装上了。所以大约10分就安好了,拿出helloworld,cargo build,cargo run,也能通过了。后来发现R在文档和库管理这一块是不是要比C++这几十年的老 将好很多呢,虽然很久没用C++,不知道发展了没有,感叹时代真是进步太大了。R的学习资料,网上有太多电子版,网页搜索查询方便,库,文档,规范也自动, 这种方便性真是让人爽快,不说别的了,还是挺推荐一学的。
任务
以前有一个模拟访问网页的python,全套代码就在里面,就剩下要了解R的语法和库就能完成任务了。于是了解reqwest是模仿request来的就用它了。结果它总是aynsc方法,看着头大,怕是掌握不住,于是就找到了reqwest::blocking这就顺利多了。还是习惯老方法。不过完成了任务就可以尝试新的了。剩下的是cookies。好在,目前的版本一步启用,
use reqwest::blocking::Client;
let client = Client::builder().cookie_store(true).build()?;
这就具备第一个轮子了。在登陆密码的以后,来了一个成功地址,做下一步的引导,结果因为这个地址,没有mut,而初始化成了,空。造成下一步,成功后也无法更新。这就让后面的所有请求是失败的。我一开始一直在怀疑cookie不能跨域fun。因为在一个fun里是好的。为此还找了cookiestore的本地文件json在实现。结果还是一样。直到后来找到了真实原因是一个变量可变的声明,
- 建立图形界面,调查对比后使用slint。
- 提交reqwest,分form.和json数据,cookie保存登陆状态,取回response并且regex分析结果,解析json结果。
- 更新界面状态,使用两个线程,一个交互web server结果保存在全局变量,一个刷新全局变量到界面状态。
- 编码用户密码以方便登陆,用户明文到AES和MD5加密,然后post去后台。
按部就班
老实的看了几个小时的教程,参数,变量,引用,数组,字符串。发现这个言语会劲量发现错的,直到按他要求来,才能通过,当然所有语言都这样。但是还是挺喜欢他的味道。和js,python形成鲜明的对比。 fn要用什么参数,传回什么类型,都要提前说好。而且,Result,Option,这样的东西,? <>这样的字符。都有自己的用处。接下了学了要用到的regex。就像reqwest、它要实现的功能都是老的,只有工具是新的。而且说心里,它跨平台,在鸿蒙也是能跑的,而且资源这么多,多好。regex r#“”#这是原始字符。以前那些提取,基本是照样出来的。
图形界面
捎带又了角一个新的slint框架,他是跨语言的,有自己的slint文件,进行窗口程序的布局。安装也像R一样,又无声又快,只是我没在vscode上,找到可拖放的插件。 在线的倒是有一个。用了半天时间,放了两个输入,一个状态,一个计数按钮。 这是从它的github,example下载来的。cargo build,cargo run。 一下就打开了。想像有一天在鸿蒙也hell world一下。但是真想不到有什么像样的任务要做。 它的in- out变量,可以在main中,set, get。在完成了后台以后,这里有一个小难点。就是状态的适时刷新。
Cargo.toml
[package]
name = "slint-rust-template"
version = "0.1.0"
edition = "2021"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]
slint = "1.7.2"
reqwest = { version = "0.12.7", features = ["json", "cookies","blocking","gzip"] }
tokio= {version= "1" ,features= ["full"] }
regex = "1.10.6"
#recode_rs="1.0.6"
encoding_rs="0.8.34"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
main.rs
// Prevent console window in addition to Slint window in Windows release builds when, e.g., starting the app via file manager. Ignored on other platforms.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod wjc;
use slint::Weak;
use wjc::kkuser;
use std::error::Error;
use std::sync::MutexGuard;
//use reqwest::Client;
use reqwest::blocking::Client;
use std::{thread, time::Duration};
use reqwest;
use regex::Regex;
use std::collections::HashMap;
slint::include_modules!();fn main() -> Result<(), Box<dyn Error>> {let ui = AppWindow::new()?;let handle_weak = ui.as_weak();let thread = std::thread::spawn(move || {//更新状态loop{handle_weak.upgrade_in_event_loop(move |handle|{ unsafe { handle.set_counter(kkuser::progbar);handle.set_status(kkuser::thestat.unwrap().into());}});thread::sleep(Duration::from_millis(500));}});ui.on_request_increase_value({let ui_handle = ui.as_weak();move || {let ui = ui_handle.unwrap();ui.set_counter(ui.get_counter() + 0.01);kkuser::test( );}});ui.run()?;Ok(())
}
感受一下,另一个主文件
appwindow.slint
export component AppWindow inherits Window {in-out property <float> counter: 0.42;in-out property <string> user: "";in-out property <string> status: "";in-out property <string> pass: "";callback request-increase-value();preferred-width: 600px;VerticalBox {Text {text: "用户:";}LineEdit{text<=> root.user;placeholder-text:"";}Text {text: "密码:";}LineEdit{text <=> root.pass;placeholder-text: "";}ProgressIndicator {preferred-width: 100%;height: 25px;progress <=> counter;}Text {text: "状态: \{root.status}用户: \{root.user}密码: \{root.pass}";}Button {text: "登陆";clicked => {root.request-increase-value();}}}
}
完成上线
前面的reqwest中的cookie解决以后,用了一天,折腾regex,把以前定义的两三个提取,请求,再实现了一把。 又细细看了几个regex演示。学不来,学不会, 这玩意真是和R语言一样,太复杂了。我只是按照旧方式实现了。然后,任务做成了长时的。界面就在转圈。于是在改成,后才thread前。我试着让任务和界面通信。把ui传递给,网页处理程序。结果总是不行。然后找了共享全局变量的办法,static mut &。这一串下来,把全局变量,从main,移动到了reqwest主程序的模块。让它处一个独立thread、去完成上线。上main里的ui,独立运行一个loop。长久的2秒,取一个全局变量,set给一个界面元素。到于slint 里的todolist。model这一类的代码,看得一头雾水。有点早。
在main.rs下建立wjc文件夹,作为mod在练习。建立两个文件,一个
mod.rs
pub mod kkuser;
pub mod jscrypto;
kkuser.rs
use reqwest::blocking::Client;
use reqwest;
use regex::Regex;
use std::{collections::HashMap, fmt::format};
use std::error::Error;
use reqwest::{cookie::Jar, Url};
use serde::{Deserialize, Serialize};
use std::{thread, time::Duration};
use serde_json::json;
// 共享状态
pub static mut thestat: Option< &str> = Some("");
pub static mut progbar:f32=0.001;
pub struct KKUser {active: bool,username: String,passwd: String,client: Client,}
pub fn build_kkuser(username: String, passwd: String) -> Result<KKUser,Box<dyn Error>>{let client = Client::builder().cookie_store(true).build()?;let ret= KKUser {active: false,username,passwd,client,};Ok(ret)}
impl KKUser {fn getloginurl(&self)->Result<String,Box<dyn Error>>{let re = Regex::new(r#"form_login_true" action="(.+?)""#).unwrap();let ret =self.client.get(BURL).send()?.text_with_charset("GBK")?;let cap=re.captures(&*ret).unwrap() ; println!("{:?}",&cap[1]);let id=String::from(&cap[1]);Ok(id)}pub fn login(&self )->Result<bool,Box<dyn Error >> {let id=self.getloginurl().unwrap(); // let check=self.getloginurl(&client).unwrap();let var_name = format!("{BURL}{id}");let mut map = HashMap::new();map.insert("u_dlcode", self.username.as_str());map.insert("p_dlcode", self.passwd.as_str());let ret:String = self.client.post(var_name).form(&map).send()?.text_with_charset("GBK")?;println!("{ret}\n");assert_eq!(true,ret.contains("home"));Ok(ret.to_string().contains("home"))}}
pub fn test() -> Result<(), Box<dyn Error>> {let handle= std::thread::spawn(||{let u =build_kkuser("V/JNlfP3SBG8tUJW5tIAo+UogWKJ6StCzwbt4zzm4=".to_string(), "E1Kf42cdpAwXknHXIy6eqIDhtQj85wCqwer6nUTzw".to_string()).unwrap(); let r=u.login().unwrap() ;let ee=format!("{r}");u.v_jiaru().unwrap();//更新全局变量,用时间较长。u.v_ksxx( ).unwrap() ;Ok(())}
设置密码
这个网站的密码和用户名是AES-MD5,加密的串。算法是js实现 的、为模拟用的是现在加密过的,为了真实使用,还需要有自己的加密算法。由于是浏览器 的算法,我就算是web从服务器来一个询问都是做不到的。为此大学AES一天24小时。也考虑从rust,访问js脚本和语句。用了两个库,都是失败的。虽然有声称可用的。我想,他会加大程序 的体积和依赖外部环境。失去灵动能力。无耐,rust本身,一大堆的半成品。从中总算发现一个现成的实现。其实是发现了两个,一个不含ZeroPading。是js正用的。另一个倒是含有。我算过了大概的一致参数,却不能得到一致结果。后来就想改写js到rust。https://www.codeconvert.ai/free-converter 它会转换js到R代码,在折腾了快一半的时候,深感难。后来看AES的文章说,算法和参数一样,就会有一样的结果。我就又回头比对参数。从cha数组 u8,数组,分析,第个参数,是传过去的什么值。 型号浏览器devtool。看起js的内容,那太方便。才知道刚好差不多。而rust最终给的 [u8] 不是最后js得到的,js最后很像BASE64,最后证明真是,完成后的长充40-43,用parase,解码成bytest、长度刚好32bits。这和rust取得的结果也挺像的。于是base64,处理过。js和R终于成功会合。另外就md5是套在密码外,然后给AES处理的。于是这就好办了。R有很标准的MD5. 有一个点是,处理出的结果还是 [u8].可以直接做AES的输入。但是要是拿来用,就又不对了。 感谢js的直观。它的md5,得到的u8的十六进制小写字符串。然后给了AES。这就好了,R,结果又安装了个小库, 只为了转成十六进制。看来,语言全靠外挂,怪不得可以跑嵌入式400K内存的板子。 我猜也许AI可以做到很多,我还是纯靠搜索了。
在Cargo.toml加入
[dependencies]aes="0.8.4"block-padding ="0.3.3"cbc="0.1.2" base64="0.22.1"hex-literal="0.4.1" md-5 = "0.10.6"data-encoding = "2.6.0"
在wjc目录建立新文件jscrypto.rs
在同目录下的kkuser.rs添加use super::jscrypto ;以使用其功能
//前端js,使用crypto-js对数据进行AES加密
//function js_encrypt(text){
//var key = CryptoJS.enc.Latin1.parse('1E785CMD585LLS4S');//为了避免补位,直接用16位的秘钥
// var iv = CryptoJS.enc.Latin1.parse('1234431890129056');//16位初始向量
// var encrypted = CryptoJS.AES.encrypt(text, key, {
// iv: iv,// mode:CryptoJS.mode.CBC,
// padding:CryptoJS.pad.ZeroPadding
//use std::char;
use block_padding::*;
use data_encoding::{HEXLOWER, DecodeError};
use std::error::Error;
use base64::prelude::*;use md5::{Md5, Digest};
use aes::cipher::{ BlockEncryptMut, KeyIvInit};
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;pub fn cry_AES(input: &str) -> Result<String, Box<dyn Error>> {let mut key= *b"1E785CMD585LLS4S"; let mut iv=*b"1234431890129056";let mut buf = [0u8; 48];let pt_len = input.len();buf[..pt_len].copy_from_slice(&input.as_bytes());let ct =Aes128CbcEnc::new(&key.into(), &iv.into()).encrypt_padded_mut::<ZeroPadding>(&mut buf, pt_len).unwrap();let bstr =BASE64_STANDARD.encode(ct);Ok(bstr)}
pub fn test() {let mut key= *b"1E785CMD585LLS4S"; let mut iv=*b"1234431890129056";let ct = cry_AES("username");println!("{:?}",ct.unwrap());let mut hasher = Md5::new();hasher.update(b"passwd");let mdu8 = hasher.finalize();let encoded = HEXLOWER.encode(&mdu8);println!("{:?}", cry_AES(encoded.as_str()).unwrap() );}fn main (){test();
}
整理完毕
至此完成,生成的程序10M上下,一个前台窗口,一个后台任务。点一下动一下。我是在苹果Mac上开发的,它 的虚拟机是一个win11 X64,拷贝工程前,删除了target目录,才让移动的,不然动不了。也不知道累积到了几百M、 拷贝过去,cargo build
cargo build --release ,都是干一会就好,本来也没啥内容。 把结果运行一下。换个目录再运行一下。感觉还是蛮爽的。
去年做过一个python jupyter下的,相似程序。它在server上运行,是python在wedget编程,后而传给celery任务。我觉得也挺好的,有容了再提交一篇。
相关文章:
RUST语言的初印象-从一个模拟登陆谈起-slint+reqwest+aes
本文就一个做了三四天的小程序讲第一次学用RUST的感受,内附代码。 了角语言 从一些渠道听说了R,这个字母挺魔性,那个文章说C和R的团体已经上升到了宗教崇拜的高度,然后,我觉得必 有过人之处,大约10年没碰…...
HBase批量写入优化
HBase批量写入性能优化 对于HBase的批量写入性能优化,可以考虑以下几点: 1.批量写入操作:使用HBasef的批量写入操作可以显著提高性能。将多个写入操作放在一个批次中一起提交。这样可以减少网络通信开销和减少多次写入操作的开销。方法不限。…...
江协科技STM32学习- P19 TIM编码器接口
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...
文件上传、重定向、Gin路由
文件上传 单个文件上传 index.html 文件上传前端页面代码: <!DOCTYPE html> <html lang"zh-CN"> <head><title>index</title> </head> <body> <form action"/upload" method"post"…...
躺平成长:微信小程序运营日记第二天
在进行属于生活的开源之后,自己更加感受到自己存在的渺茫,同时更加开始深刻领会,开源的重要性,在开源,开放,创造,再创新的思维模式下,不发布八部金刚功相关的训练视频,自…...
三分钟速览:Node.js 版本差异与关键特性解析
Node.js 是一个广泛使用的 JavaScript 运行时环境,允许开发者在服务器端运行 JavaScript 代码。随着技术的发展,Node.js 不断推出新版本,引入新特性和改进。了解不同版本之间的差异对于开发者来说至关重要。以下是一个快速指南,帮…...
git创建新分支
git创建新分支 1.先在gitLab上New branch. 2.本地右键git小乌 - /切换/检出-创建新分支,分支名称和上一步创建的一样。 最后记得改个文件提交下,看看gitLab上是否提交成功。...
Chip-seq数据分析处理流程
一、处理过程 要处理 SRR14879780 的 ChIP-seq 数据并进行基序分析(包括比对到参考基因组 hg38.fasta 和峰值调用),你可以按照以下步骤操作,并使用相应的代码。每个步骤会涉及一些常用的生物信息学工具,如 FastQC、Tr…...
spring boot3.2.x与spring boot2.7.x对比
Spring Boot 3.2.x 相比 Spring Boot 2.7.x 带来了许多重要的变化、新特性以及性能改进。这些新功能不仅提升了开发者的效率,还优化了应用的性能和安全性。以下是两者的主要差异、优势以及使用说明: 1. JDK 17 支持 Spring Boot 2.7.x 支持 JDK 8 至 J…...
Vue2(十三):路由
一、路由的简介 vue-rooter:是vue的一个插件库,专门用来实现SPA应用 1.对SPA应用的理解 1、单页 Web 应用(single page web application,SPA)。 2、整个应用只有一个完整的页面 index.html。 3、点击页面中的导航链…...
Java并发:互斥锁,读写锁,公平锁,Condition,StampedLock
阅读本文之前可以看一看 Java 多线程基础: Java:多线程(进程线程,线程状态,创建线程,线程操作) Java:多线程(同步死锁,锁&原子变量,线程通信&…...
在 Linux 中,要让某一个线程或进程排他性地独占一个 CPU
文章目录 1. CPU 亲和性(CPU Affinity)2. 中断隔离(IRQ Isolation)3. 系统 tickless 模式(NoHZ Mode)4. 实时调度策略5. CPU 隔离(CPU Isolation)和 Full CPU Isolation实现最低的延迟抖动在 Linux 中,要让某一个线程 排他性地独占一个 CPU,并且进一步隔离中断(包括…...
滚雪球学MySQL[7.3讲]:数据库日志与审计详解:从错误日志到审计日志的配置与使用
全文目录: 前言7.3 日志与审计1. 日志类型与配置1.1 错误日志(Error Log)配置错误日志使用场景案例演示 1.2 慢查询日志(Slow Query Log)配置慢查询日志使用场景案例演示 1.3 查询日志(General Query Log&a…...
网关的作用及其高可用性设计详解
引言 在现代分布式系统架构中,网关(Gateway)是一个关键组件。它作为客户端与后端服务之间的桥梁,不仅提供了请求路由、负载均衡、安全认证、流量控制等功能,还能够保护后端服务的安全和稳定性。网关的设计和高可用性对…...
Vortex GPGPU的github流程跑通与功能模块波形探索
文章目录 前言一、跟着官方文档走一遍二、cache子模块的波形仿真2.1 必要的文件内容解释2.2 cache子模块波形仿真——目前环境没啥问题了,就vcd因为配置问题出不来 总结 前言 看了那么久的verilog代码和文档,但还是没怎么接触过Vortex GPGPU全流程跑通与…...
10.2 Linux_并发_进程相关函数
创建子进程 函数声明如下: pid_t fork(void); 返回值:失败返回-1,成功返回两次,子进程获得0(系统分配),父进程获得子进程的pid 注意:fork创建子进程,实际上就是将父进程复制一遍作为子进程&…...
【深度学习基础模型】玻尔兹曼机BM|受限玻尔兹曼机RBM|深度置信网络DBN详细理解并附实现代码。
【深度学习基础模型】玻尔兹曼机Boltzmann machines (BM)|受限玻尔兹曼机Restricted Boltzmann machines (RBM)|深度置信网络Deep belief networks (DBN)详细理解并附实现代码。 【深度学习基础模型】玻尔兹曼机Boltzmann machines (BM)|受限玻尔兹曼机Restricted Boltzmann m…...
滑动窗口->dd爱框框
1.题目: 2.题解: 2.1为什么用滑动窗口优化: 因为元素都是大于0的 所以:当找到大于等于x的值时,right可以不用返回 两个指针都往后走;因此可以使用滑动窗口优化暴力解法 2.2:滑动窗口具体使用步…...
Python从入门到高手4.1节-掌握条件控制语句
目录 4.1.1 理解条件控制 4.1.2 if, elif, else 4.1.3 条件表达式 4.1.4 条件控制可以嵌套 4.1.5 if语句的三元运算 4.1.6 国庆节快乐 4.1.1 理解条件控制 在日常生活中,我们常喜欢说如果, "如果怎么样,那么就会怎么样"。"如果&qu…...
使用Qt实现实时数据动态绘制的折线图示例
基于Qt的 QChartView 和定时器来动态绘制折线图。它通过动画的方式逐步将数据点添加到图表上,并动态更新坐标轴的范围,提供了一个可以实时更新数据的折线图应用。以下是对代码的详细介绍及其功能解析: 代码概述 该程序使用Qt的 QChartView…...
【人人保-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...
Redis6 多线程模型
优质博文:IT-BLOG-CN 一、单线程的优缺点 对于一个请求操作Redis主要做3件事情:从客户端读取数据/解析、执行Redis命令、回写数据给客户端。所以主线程其实就是把所有操作的这3件事情串行一起执行,因为是基于内存,所以执行速度非…...
Python的异步编程
什么是协程? 协程不是计算机系统提供,程序员人为创造。 协程也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。 实现协程有那么几种方法: greenlet&…...
初识Linux · 进程等待
目录 前言: 进程等待是什么 为什么需要进程等待 进程等待都在做什么 前言: 通过上文的学习,我们了解了进程终止,知道终止是在干什么,终止的三种情况,以及有了退出码,错误码的概念ÿ…...
面向对象建模
UML 关系 UML 关系主要有:依赖、关联、聚合、组合、实现、继承。 类图 #mermaid-svg-jcAjcVcPmgmWDpcI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jcAjcVcPmgmWDpcI .error-icon{fill:#552222;}#m…...
MetaJUI v0.4 遇到的一些问题及解决办法记录
1、Unity3d 版本 2022.3.29f1。 2、MetaJUI v0.4 的下载,https://download.csdn.net/download/xingchengaiwei/89334848 3、将MetaJUI v0.4解压,用Unity3d 打开项目,会出现如下问题,按照图中提示操作即可。 4、打开工程后会出现…...
从零开始学习OMNeT++系列第二弹——新建一个OMNeT++的工程
上一篇第一弹介绍了OMNeT是什么以及如何安装OMNeT,现在来说一下如何新建一个自己的OMNeT的工程。 在 Omnet安装完成后,samples/tictoc 中有该例子的完整文件,你可以立刻运行该文件看他是怎么工作的,不过更推荐按接下来的步骤一步…...
【Android】布局优化—include,merge,ViewStub的使用方法
引言 1.重要性 在Android应用开发中,布局是用户界面的基础。一个高效的布局不仅能提升用户体验,还能显著改善应用的性能。随着应用功能的复杂性增加,布局的优化变得尤为重要。优化布局能够减少渲染时间,提高响应速度,…...
传奇外网架设教程带图文解说—Gee引擎
架设前准备工作: ①通过百度网盘下载版本、补丁、客户端和DBC2000。版本解压到D盘,客户端解压到D盘或是E盘,补丁先不解压 ②安装和配置DBC2000,有些版本不一定用的是DBC2000数据库,看引擎默认的数据库是哪个 DBC数据…...
MySQL | excel数据输出insert语句
需求 在日常生产运维过程中,有很多需要进行人工梳理的excel数据,到了研发这一侧需要转为sql语句进行数据修正,如何输出insert插入语句? 方案 在空白列插入,选择需要的列 "INSERT INTO tab_name1 (name, desc) …...
公司自己的网站叫什么/网站搭建需要什么技术
本文就来看看在Spring Boot中MyBatis要如何使用。 工程创建 首先创建一个基本的Spring Boot工程,添加Web依赖,MyBatis依赖以及MySQL驱动依赖,如下: 最简单的SpringBoot整合MyBatis教程 创建成功后,添加Druid依赖&#…...
做擦边网站 服务器/google免登录网页版
课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijian/article/details/8635385【项目3-用结构体数组作计算】接项目2,(1)从文件中读出数…...
办网多少钱/官网seo哪家公司好
智能停车场管理系统全部采用计算机自动管理,监视车库情况,需要时,管理人员通过主控计算机对整个停车场情况进行监控管理。 可实时监察每辆车的出入情况,并自动记录,包括内部车辆的出入时间、车位号、停车费等信息。同时…...
我国最新疫情最新消息/网站seo推广招聘
背景相信大家都知道电脑自带的记事本【notepad】,也叫记事簿,这个记事本可能大家都有在用,比如在网页上复制一段有着各种超链接、带格式的文字,想要快速去掉格式,聪明的人一般都会直接复制粘贴到记事本里,然…...
网站建设 方案下载/网络软件开发
背景 随着产品功能不断的迭代,总会有需求希望在保证不影响其他区域功能的前提下,在某一区域实现根据选择器切换不同的内容显示。 苹果并不推荐嵌套滚动视图,如果直接添加的话,就会出现下图这种情况,手势的冲突造成了体…...
天津集体建设用地出售 网站/怎么做优化关键词
文章目录1. 背景介绍2. 跨云商内网打通2.1 阿里云环境安装部署2.1.1 加载驱动模块2.1.2 添加 GRE 隧道开机启动脚本2.1.3 配置 iptalbes 规则2.1.4 在其他节点配置路由2.2 华为云上安装部署2.2.1 加载驱动模块2.2.2 添加 GRE 隧道开机启动脚本2.2.3 配置 iptalbes 规则2.2.4 在…...