#小森林 已更新到 Mastodon v3.4.1 (实际上是更新到latest commit),两三个月没合代码,rebase了一早上
Git 新加了两个命令:git switch 用来切换分支,git restore 用来恢复原样,可以取代 git checkout。
https://www.banterly.net/2021/07/31/new-in-git-switch-and-restore/
KMP算法实现字符串匹配和替换,JS ver.
class Solution {
public static matchTable(str: string) {
const strLen = str.length;
const table: number[] = [];
for (let pos = 0; pos < strLen; pos++) {
let prefix: string[] = [];
let suffix: string[] = [];
for (let cursor = 0; cursor <= pos; cursor++) {
prefix.push(str.slice(0, cursor));
suffix.push(str.slice(cursor + 1, pos + 1));
}
prefix = prefix.filter((s) => s);
suffix = suffix.filter((s) => s);
const match: string[] = [""];
prefix.forEach((pf) => {
suffix.forEach((sf) => {
if (pf === sf) {
match.push(pf);
}
});
});
table.push(Math.max(...match.map((s) => s.length)));
}
return table;
}
public static matchString(target: string, search: string): number {
const matchTable = this.matchTable(search);
const targetLen = target.length;
const searchLen = search.length;
if (targetLen < searchLen) return -1;
let pos = 0;
while (pos <= targetLen - searchLen) {
for (let cursor = 0; cursor < searchLen; cursor++) {
if (target[pos + cursor] === search[cursor]) {
if (cursor === searchLen - 1) {
return pos;
} else {
continue; // for
}
} else {
pos += cursor + 1 - matchTable[cursor];
break; // for
}
}
}
return -1;
}
public static replace(A = "hello world", B = "hello", C = "Mars") {
const lenA = A.length;
const lenB = B.length;
let res = A;
const pos = this.matchString(res, B);
if (pos >= 0) {
res = res.slice(0, pos) + C + res.slice(pos + lenB, lenA);
return res;
} else {
this.replace(res, B, C);
}
return res;
}
}
console.log(Solution.replace("hello world", "world", "mars"));
Vue3 useKeepAliveWindowScrollTop hook
import { onDeactivated, watch, onActivated } from 'vue'
import { useWindowScroll } from '@vueuse/core'
import { useState } from '@/hooks'
export default function () {
const { scrollTop, scrollLeft } = (function () {
const { x, y } = useWindowScroll()
return { scrollTop: y, scrollLeft: x }
})()
const [scrollTopCache, setScrollTopCache] = useState(0)
const [isScrollTopSet, setIsScrollTopSet] = useState(false)
watch(scrollTop, (value) => {
if (!isScrollTopSet.value) return
setScrollTopCache(value)
})
onActivated(() => {
window.scrollTo(scrollLeft.value ?? 0, scrollTopCache.value)
setIsScrollTopSet(true)
})
onDeactivated(() => {
setIsScrollTopSet(false)
})
}
Congratulations to Day 3's winners @ElySimpTq, @Wolfthedark15! Please send the required information to arknights.event@yo-star.com. Retweet the original post each day and you might have a chance to win all the rewards!
#ArknightsCelebration #Arknights #Yostar
Arknights_EN: Dear Doctor, we're holding a giveaway event to celebrate Arknights' 1.5 anniversary. Retweet this post with your wish (words or images) for Arknights and 2 tags: #ArknightsCelebration #Arknights, and you will get a chance to win the following rewards!
#Yostar
Update
@use 'sass:math';
@mixin _flex-gap($gap, $row: true, $wrap: false) {
$margin: math.div($gap, 2);
$transform: calc(#{$margin} * -1);
$size: calc(100% + #{$margin} * 2);
@if $row {
margin-left: #{$transform};
width: #{$size};
} @else {
margin-top: #{$transform};
height: #{$size};
}
> * {
@if $row {
margin-left: $margin;
margin-right: $margin;
} @else {
margin-top: $margin;
margin-bottom: $margin;
}
}
}
@mixin flex-gap($gap, $flex-flow: 'row nowrap') {
@if $flex-flow== 'row nowrap' or $flex-flow== 'row-reverse nowrap' {
@include _flex-gap($gap, true);
} @else if $flex-flow== 'column nowrap' or $flex-flow== 'column-reverse nowrap' {
@include _flex-gap($gap, false);
} @else {
@include _flex-gap($gap, true, true);
@include _flex-gap($gap, false, true);
}
}
Chinese 🇨🇳 / Dictatorial Admin / Mastodon Code Contributor / 摸鱼技术布道师
Steam: https://steamcommunity.com/id/MashiroBest
Epic: https://store.epicgames.com/en-US/u/d211c824cbd94aaeba898db6bb823ff7
原批交流群:966322309