首页
友情链接
精美壁纸
给我留言
更多
关于我
Search
1
uniapp Click点击事件冲突解决
4,587 阅读
2
【插件】UNI APP 实现商米打印机功能支持T1,T2,V2机型
4,002 阅读
3
【测试可用】个人码免签支付系统源码/免签支付系统/微信支付平台
2,040 阅读
4
windows10下docker:给已存在的容器添加端口映射的方法
1,253 阅读
5
Java Validation参数校验注解使用
1,235 阅读
Java
Spring Boot
Spring Mvc
Java基础
进阶知识
前端
uniapp
小程序/公众号
JavaScript
HTML/CSS
Vue
PHP
开源软件
商城
营销工具
开发工具
视频/教程
Discuz主题/插件
typecho主题/插件
SEO杂谈
数据库
MongoDB
MySQL
Redis
单片机
概念说明
电路相关
Python
devops
docker
k8s
linux
职场杂谈
登录
/
注册
Search
标签搜索
python
mysql
人人商城
php
java
docker
typecho
插件
微擎
seo
spring boot
discuz
队列
uni-app
phpcms
教程视频
开源系统
源码
工具
css
哈根达斯
累计撰写
108
篇文章
累计收到
161
条评论
首页
栏目
Java
Spring Boot
Spring Mvc
Java基础
进阶知识
前端
uniapp
小程序/公众号
JavaScript
HTML/CSS
Vue
PHP
开源软件
商城
营销工具
开发工具
视频/教程
Discuz主题/插件
typecho主题/插件
SEO杂谈
数据库
MongoDB
MySQL
Redis
单片机
概念说明
电路相关
Python
devops
docker
k8s
linux
职场杂谈
页面
友情链接
精美壁纸
给我留言
关于我
搜索到
108
篇与
哈根达斯
的结果
2021-11-22
css实现文字超过两行截取替换省略号方案
在页面设计众,设计给出的标题常常为限制2行显示,超出部分以省略号形式展示,该功能可直接使用css实现实现方案结合overflow使用.p{ text-overflow: -o-ellipsis-lastline; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; /* 多少行 */ line-clamp: 2; /* 多少行 */ -webkit-box-orient: vertical; }兼容性说明-webkit-line-clamp 是一个 不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。为了实现该效果,它需要组合其他外来的WebKit属性。常见结合属性:display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。-webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。text-overflow 可以用来多行文本的情况下,用省略号“...”隐藏超出范围的文本 .
2021年11月22日
475 阅读
0 评论
0 点赞
2021-11-08
Vue倒计时组件
开源cool的倒计时组件,修改后也可直接使用在网页中,非常好用的一个倒计时控件1. 组件源码可以在cool uni中下载<template> <div class="cl-countdown"> <template v-for="(item, index) in list"> <div class="cl-countdown-item" :key="index" :style="[customStyle]" v-if="item.visible"> <span class="cl-countdown__number" :style="[numberStyle]">{{ item.value }}</span> <span class="cl-countdown__splitor" :style="[splitorStyle]">{{ item.splitor }}</span> </div> </template> <div class="cl-countdown-item" v-if="isMillisecond"> <span class="cl-countdown__number">{{ millisecond }}</span> </div> </div> </template> <script> function isArray(value) { if (typeof Array.isArray === 'function') { return Array.isArray(value); } else { return Object.prototype.toString.call(value) === '[object Array]'; } } /** * countdown 倒计时 * @description 倒计时, 支持布局显示, 自定义样式 * @property {String, Array} splitor 图片链接 * @property {Array} layout 布局, ["day", "hour", "minute", "second"] * @property {String} mode default 默认 | simple 是否精简:为00时自动隐藏,默认dfault * @property {Number} day 还有多少天 * @property {Number} hour 还有多少小时 * @property {Number} minute 还有多少分钟 * @property {Number} second 还有多少秒 * @property {Date, String} datetime 结束时间 * @property {Boolean} isMillisecond 是否带有毫秒 * @property {Object} customStyle 自定义样式 * @property {Object} numberStyle 数字样式 * @property {Object} splitorStyle 分隔符样式 * @example <cl-countdown :day="5" /> */ export default { name: "countdown", props: { // 分隔符 [day, hour, minute, second] splitor: { type: [String, Array], default: "default" }, // 布局 layout: { type: Array, default: () => ["day", "hour", "minute", "second"] }, // simple 是否精简:为00时自动隐藏 mode: { type: String, default: "default" }, // 还有多少天 day: { type: Number, default: 0 }, // 还有多少小时 hour: { type: Number, default: 0 }, // 还有多少分钟 minute: { type: Number, default: 0 }, // 还有多少秒 second: { type: Number, default: 0 }, // 结束时间 datetime: [Date, String], // 是否带有毫秒 isMillisecond: Boolean, // 自定义样式 customStyle: Object, // 数字样式 numberStyle: Object, // 分隔符样式 splitorStyle: Object }, data() { return { timer: null, millisecondTimer: null, syncFlag: false, seconds: 0, list: [], millisecond: 9, status: false }; }, watch: { day() { this.changeFlag(); }, hour() { this.changeFlag(); }, minute() { this.changeFlag(); }, second() { this.changeFlag(); }, datetime() { this.changeFlag(); } }, beforeDestroy() { this.clear(); }, created() { this.start(); }, methods: { // 转成秒 toSeconds({ day = 0, hour = 0, minute = 0, second = 0, datetime }) { if (datetime) { return ( (new Date(datetime.replace(/-/g, "/")).getTime() - new Date().getTime()) / 1000 ); } else { return day * 60 * 60 * 24 + hour * 60 * 60 + minute * 60 + second; } }, // 开始倒计时 start(options) { let { day, hour, minute, second, datetime } = options || {}; if (!day) { day = this.day; } if (!hour) { hour = this.hour; } if (!minute) { minute = this.minute; } if (!second) { second = this.second; } if (!datetime) { datetime = this.datetime; } this.seconds = this.toSeconds({ day, hour, minute, second, datetime }); this.next(); }, // 继续倒计时 next() { if (this.seconds <= 0) { return; } if (this.status) { return; } this.status = true; // Start coundown const next = () => { this.countDown(); if (this.seconds <= 0) { this.done(); return; } else { this.seconds--; this.timer = setTimeout(next, 1000); } }; // Use setTimeout instead setInterval next(); // milli second if (this.isMillisecond) { const next = () => { this.millisecond--; if (this.millisecond < 0) { this.millisecond = 9; } this.millisecondTimer = setTimeout(next, 100); }; next(); } }, // 停止 stop() { this.clear(); this.$emit("stop"); }, // 结束 done() { this.clear(); this.$emit("done"); }, // 清除定时器 clear() { clearTimeout(this.timer); clearTimeout(this.millisecondTimer); this.timer = null; this.millisecondTimer = null; this.status = false; }, // 倒计时执行 countDown() { let seconds = this.seconds; let [day, hour, minute, second] = [0, 0, 0, 0]; day = Math.floor(seconds / (60 * 60 * 24)); hour = Math.floor(seconds / (60 * 60)) - day * 24; minute = Math.floor(seconds / 60) - day * 24 * 60 - hour * 60; second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60; if (day < 10) { day = "0" + day; } if (hour < 10) { hour = "0" + hour; } if (minute < 10) { minute = "0" + minute; } if (second < 10) { second = "0" + second; } const obj = { day, hour, minute, second }; let flag = day === "00"; this.list = this.layout.map((e, i) => { let item = { value: obj[e], splitor: this.splitorText(i), visible: this.mode === "simple" ? (flag ? obj[e] !== "00" : true) : true }; if (flag) { flag = obj[e] === "00"; } return item; }); this.$emit( "change", this.list.map(e => e.value) ); }, // 分隔符内容 splitorText(i) { let arr = []; if (isArray(this.splitor)) { arr = this.splitor; } else { switch (this.splitor) { case "cn": arr = ["天", "时", "分", "秒"]; break; case "en": arr = ["Day", "Hour", "Minute", "Second"]; break; case "": case false: case null: arr = ["", "", "", ""]; break; case "default": default: arr = ["天", ":", ":", ""]; break; } } return arr[i]; }, changeFlag() { this.$nextTick(() => { this.start(); }); } } }; </script> <style lang="scss" scoped> .cl-countdown { display: inline-flex; &__number { display: inline-block; height: 14px; font-size:14px; line-height: 14px; text-align: center; border-radius: 6px; } &__splitor { font-size:14px; } &-item { display: flex; align-items: center; &:first-child { .cl-countdown__number { margin-left: 0; } } } } </style> 2. 组件使用<countdown :second="3600" splitor="cn"></countdown>3. 本代码说明代码使用来自cool官方组件修改,查看官方组件文档di'zhi cool官方文档
2021年11月08日
312 阅读
0 评论
0 点赞
2021-09-26
mysql 创建用户
mysql 8.0 以下创建-- 以下命令会创建一个可以任何IP主机 访问 的用户,并对db_name数据库具有 所有权限操作, GRANT ALL PRIVILEGES ON db_name.* TO 'username'@'%' IDENTIFIED BY '访问密码' WITH GRANT OPTIONmysql 8.0及以上创建 -- 创建账户(% 代表所有IP) create user 'username'@'%' identified by 'paaswrod'; -- 赋予权限,with grant option这个选项表示该用户可以将自己拥有的权限授权给别人 grant all privileges on gxxblw_db.* to 'username'@'%' with grant option; -- 改密码&授权超用户,flush privileges 命令本质上的作用是将当前user和privilige表中的用户信息/权限设置从mysql库(MySQL数据库的内置库)中提取到内存里 flush privileges;
2021年09月26日
161 阅读
0 评论
0 点赞
2021-09-01
Java Stream 流式编程
前言在很多语言中都会有 map、reduce、filter 等高阶函数对应的流式编程。那么对应 Java 中的功能就是 Stream 操作。// 生成 1357 并打印Arrays.stream(new int[] {1, 3, 5, 7}).forEach(System.out::println);复制代码所以今天就整理一下关于 Java Stream 流式编程。关于 StreamStream 是 Java8 添加的一个新的抽象称为流,可以让你以一种声明的方式处理数据。Stream 可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。Stream 流的操作是以管道的方式串起来的。管道以数据源开始,包含若干个中间操作,最终以终点操作结束。简单使用下面介绍一下在 Java 中简单的使用:Map Filter ReduceList<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9); // 求和 // Integer sumResult = list.stream().reduce(0, (a, b) -> a + b); Integer sumResult = list.stream().reduce(0, Integer::sum); // 45 System.out.println(sumResult); // 遍历数组 list.forEach(System.out::print); // 123456789 System.out.println(); // 返回数组元素的平方 List<Integer> numbersList = list.stream().map(i -> i * i).collect(Collectors.toList()); // [1, 4, 9, 16, 25, 36, 49, 64, 81] System.out.println(numbersList); List<Integer> evenNumbersList = list.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()); // 筛选出数组中的偶数 [2, 4, 6, 8] System.out.println(evenNumbersList); // 筛选出数组中的奇数并返回元素的平方 List<Integer> numbers = list.stream().filter(i -> i % 2 != 0).map(i -> i * i).collect(Collectors.toList()); System.out.println(numbers);Collector一般用于 stream 操作的结束,用于对结果集做返回值的定义或高级操作。常见操作用于返回特定的集合:Collectors.toList() Collectors.toMap() Collectors.toSet() Collectors.toCollection() Collectors.toConcurrentMap()下面列举常见 demo :List<String> language = List.of("Java", "Python", "Rust", "Go", "C++", "C", "C#", "JavaScript"); // 将数组中元素转化成大写字母并用逗号拼接 String collect1 = language.stream().collect(Collectors.collectingAndThen(Collectors.joining(","), String::toUpperCase)); // JAVA,PYTHON,RUST,GO,C++,C,C#,JAVASCRIPT System.out.println(collect1); // 实现按数组元素进行分组 Map<Integer, List<String>> collect2 = language.stream().collect(Collectors.groupingBy(String::length)); // {1=[C], 2=[Go, C#], 3=[C++], 4=[Java, Rust], 6=[Python], 10=[JavaScript]} System.out.println(collect2); // 转换成字符串长度与字符串的 hash map 有冲突后者覆盖前者 Set<String> collect3 = language.stream().collect(Collectors.toCollection(HashSet::new)); // language.stream().collect(Collectors.toSet()); // [C#, Java, C++, Rust, C, JavaScript, Go, Python] System.out.println(collect3); // 转换成字符串长度与字符串的 hash map 有冲突后者覆盖前者 Map<Integer, String> collect4 = language.stream().collect(Collectors.toMap(String::length, String::new,(existing, replacement) -> existing)); // {1=C, 2=Go, 3=C++, 4=Java, 6=Python, 10=JavaScript} System.out.println(collect4);进阶使用在简单使用中都是比较常见且统一理解的例子。下面看一下一些比较复杂的例子。数据准备Person 类用到了 Lombok 的 Builder、Data 注解。@Builder(toBuilder = true) @Data class Person { private Integer height; private Integer age; private String name; private String city; } Person p1 = new Person.PersonBuilder().name("bob").height(150).city("shanghai").age(15).build(); Person p2 = new Person.PersonBuilder().name("andy").height(160).city("beijing").age(18).build(); Person p3 = new Person.PersonBuilder().name("tom").height(170).city("xian").age(19).build(); Person p4 = new Person.PersonBuilder().name("cat").height(180).city("shanghai").age(25).build(); ArrayList<Person> persons = new ArrayList<>(); persons.add(p1); persons.add(p2); persons.add(p3); persons.add(p4);实例讲解如下代码实现的功能为:将人员数组按照年龄设置额外字段将数组中人员按照城市分组组内结果如有多人取身高最高的一员// 需要关于身高的 Comparator Comparator<Person> byHeight = Comparator.comparing(Person::getHeight); Map<String, Person> collect = persons.stream().peek(item -> { String temp = item.getAge() >= 18 ? "成年" : "未成年"; item.setExtra(temp); }).collect( Collectors.groupingBy( Person::getCity, Collectors.reducing(p1, BinaryOperator.maxBy(byHeight)) ) ); // {xian=Person(height=170, age=19, name=tom, city=xian, extra=成年), shanghai=Person(height=180, age=25, name=cat, city=shanghai, extra=成年), beijing=Person(height=160, age=18, name=andy, city=beijing, extra=成年)} System.out.println(collect);
2021年09月01日
99 阅读
0 评论
0 点赞
2021-08-31
Java中ThreadLocal简单学习使用
文章目录索引ThreadLocal定义该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。以上来源官方API。大概可以总结为两点:ThreadLocal提供get/set方法,可以访问属于当前线程的变量,也就是可以保证每个线程的变量不一样。ThreadLocal使用时通常定义为private static的。从字面意思理解,可能会将ThreadLocal认为是本地线程,其实ThreadLocal并不是线程,而是线程Thread的局部变量。1、如何使用首先,定义一个private static的ThreadLocal对象。private static ThreadLocal<String> threadLocal = new ThreadLocal<>();然后每个线程可以将当前线程需要存放在局部变量中,并且可以从中获取。public void setAndGet(String name) { threadLocal.set(name); String s = threadLocal.get(); }最后在使用完之后,需要将ThreadLocal中的值移除。public void remove() { threadLocal.remove(); }2.原理那么ThreadLocal是如何做到保证每个线程get出来的数据不一样的呢?我们通过源码来看一下。public void set(T value) { Thread t = Thread.currentThread(); // 通过当前线程获取出来一个ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }我们发现在set方法中,会创建一个ThreadLocalMap,然后将要设置的值放在这个Map中,而当前这个ThreadLocal对象作为key;然后再将这个ThreadLocalMap赋值给Thread的threadLocals里。如果去看Thread类的代码会发现,在Thread类中存在两个变量threadLocals和inheritableThreadLocals,它们的类型就是ThreadLocal.ThreadLocalMap。通过下图可以看出Thread,ThreadLocal,ThreadLocalMap三者的关系。这时候我们再看看get()和remove()方法的代码。public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }可以看出来,和我们上面图中的结构一样,get()方法就是从Thread中取出来ThreadLocalMap,然后通过ThreadLocal对象作为Key取出值;remove()方法则是取出ThreadLocalMap将ThreadLocal对应的数据移除。那么ThreadLocalMap到底是什么呢?是java.util.Map接口的子类吗?我们来看源码。static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table; private int size = 0; private int threshold; // Default to 0 // 省略其他代码 }通过源码发现,ThreadLocalMap并没有实现Map接口,也没有集成其他任何的Map类。是定义在ThreadLocal类中的一个静态内部类。而它的结构和HashMap结构极其相似。有一个Entry[]数组存放数据。而这个Entry类是继承自WeakReference类的子类,这一点和HashMap有所不同。ThreadLocalMap和HashMap结构有很多不同,但是还有一点和HashMap不一样,我们来看一下ThreadLocalMap的set方法。private void set(ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; // 计算key对应放在tab中的下标 int i = key.threadLocalHashCode & (len-1); //循环遍历tab,首先获取到下标i对应的对象,如果不为空,则执行循环体 // 如果不是相同的threadLocal或者位置失效,则要寻找下一个位置。 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); // 判断与当前ThreadLocal是否是同一个对象,如果是则进行值替换,结束 if (k == key) { e.value = value; return; } // 如果k==null代表threadLocal的key失效了,将失效的key进行替换 if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }代码中循环遍历tab,首先获取到下标i对应的对象,如果不为空,则执行循环体,如果在循环体中的两个条件都不满足,则会执行nextIndex()方法,这个方法的代码如下:private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); }这个方法的逻辑就是 开放寻址法 。而HashMap则是通过 拉链法 和 rehash 来做的。3.使用场景通过上面的内容基本可以掌握ThreadLocal的基本用法,那么ThreadLocal主要在什么场景中使用呢。ThreadLocal的作用通过以上了解我们知道主要是用来做线程间数据隔离。那么在什么场景下能用到线程隔离呢?首先想到的就是SimpleDateFormat这个工具类,它不是线程安全的,可以通过ThreadLocal在每个线程中放一份,保证线程安全。还有比如说用户登录的session,或者token数据,只数据当前会话线程,也可以通过ThreadLocal存储。再比如在某些场景下,上下文数据在不同方法之间调用,传递起来非常麻烦,可以通过ThreadLocal存放,只需要在需要用到的地方获取就可以。除了这些场景,在某些框架源码中也会使用到,比如Spring中的事务也主要是通过ThreadLocal和面向切面编程AOP实现的,感兴趣的同学可以查看源码了解。4.避免踩坑内存泄漏ThreadLocalMap中的Entry的Key是一个弱引用,因此如果在使用后不调用remove方法清除掉会导致对应的value内存泄漏。所以在使用完以后一定要记得调用remove方法清除数据。
2021年08月31日
139 阅读
0 评论
0 点赞
1
...
13
14
15
...
22