0%

break

1
2
3
4
for(let i =0;i< 10;i++){
if(i>5)break
console.log(i)
}

find 或者 findIndex

  • ref 使用 aaa.value
  • reactive 类型是 object

ref 和 reactive 一个针对原始数据类型,而另一个用于对象,这两个API都是为了给JavaScript普通的数据类型赋予响应式特性(reactivity)。

  • reactive和ref都是用来定义响应式数据的,而reactive更推荐用来定义对象,ref更推荐定义基础数据类型,但是ref也可以定义数组和对象
  • 在访问数据的时候,ref需要使用.value,而reactive不需要
1
const dataAsRefs = toRefs(data);

步子比蛋大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>Hello, {{ name }}!</div>
<input v-model="name" />
<button :disabled="!isNamePresent" @click="submitName">Submit</button>
</template>

<script setup>
import { ref, computed } from 'vue'

const name = ref('')
const isNamePresent = computed(() => name.value.length > 0)

function submitName() {
console.log(name.value)
}
</script>

父子组件

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Form.vue -->
<template>
<form @submit.prevent="submitHandler">
<label>Name
<input type="text" />
</label>
<button>Submit</button>
</form>
</template>

<script setup>
function submitHandler() {
// Do something
}
</script>

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- App.vue -->
<template>
<div>Hello, {{ name }}!</div>
<Form />
</template>

<script setup>
import { ref } from 'vue'
import Form from './components/Form.vue'

const name = ref('')

function submitForm() {
console.log(name.value)
}
</script>

defineProps 和 defineEmits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!-- Form.vue -->
<template>
<form @submit.prevent="submitHandler">
<label>Name
<input v-model="name" type="text" />
</label>
<button>Submit</button>
</form>
</template>

<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:modelValue', 'submit']);

const name = computed({
get () {
return props.modelValue
},
set(val) {
emit('update:modelValue', val);
}
})

function submitHandler() {
emit('submit')
}
</script>

<!-- App.vue -->
<template>
<div>Hello, {{ name }}!</div>
<Form v-model="name" @submit="submitForm" />
</template>

<script setup>
import { ref } from 'vue'
import Form from './components/Form.vue'

const name = ref('')

function submitForm() {
console.log(name.value)
}
</script>

git pull是git fetch和git merge两个步骤的结合

vscode 的 sync 等于下面

1
2
git pull origin someBranch
git push origin someBranch

  • ~ 选择器的 相反的 “previous sibling” selector ?

几个思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
/* default link color is blue */
.parent a {
color: blue;
}

/* prev siblings should be red */
.parent:hover a {
color: red;
}
.parent a:hover,
.parent a:hover ~ a {
color: blue;
}
1
2
3
4
5
6
7
<div class="parent">
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
</div>

flex order 或者 row-reverse 。 DOM 在后但显示“在前”。

1
ul li:nth-child(-n+2)

via https://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-selector

via https://coolcssanimation.com/how-to-trigger-a-css-animation-on-scroll/


IntersectionObserver 是否可见

1
2
3
4
5
6
7
8
9
10
11
12
13
var io = new IntersectionObserver(callback, option);

// 开始观察
io.observe(document.getElementById('example'));

// 停止观察
io.unobserve(element);

// 关闭观察器
io.disconnect();

io.observe(elementA);
io.observe(elementB);

lazy load

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function query(selector) {
return Array.from(document.querySelectorAll(selector));
}

var observer = new IntersectionObserver(
function(changes) {
changes.forEach(function(change) {
var container = change.target;
var content = container.querySelector('template').content;
container.appendChild(content);
observer.unobserve(container);
});
}
);

query('.lazy-loaded').forEach(function (item) {
observer.observe(item);
});

无限滚动(infinite scroll)

1
2
3
4
5
6
7
8
9
10
11
12
var intersectionObserver = new IntersectionObserver(
function (entries) {
// 如果不可见,就返回
if (entries[0].intersectionRatio <= 0) return;
loadItems(10);
console.log('Loaded new items');
});

// 开始观察
intersectionObserver.observe(
document.querySelector('.scrollerFooter')
);

ResizeObserver

观测 resize

scrollIntoView 到中间

https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

scrollIntoView()

默认是

scrollIntoView(true)

也就是

scrollIntoView({block: “start”, inline: “nearest”})

false 是

scrollIntoView({block: “end”, inline: “nearest”})

参数

behavior Optional

Defines the transition animation. One of auto or smooth. Defaults to auto.

block Optional

Defines vertical alignment. One of start, center, end, or nearest. Defaults to start.

inline Optional

Defines horizontal alignment. One of start, center, end, or nearest. Defaults to nearest.

tab 尽量靠中间

1
2
3
4
5
6
7
obj.scrollIntoView(
{
behavior: 'smooth',
block: 'nearest',
inline: 'center'
}
)

16:9 固定比例的 iframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.container {
position: relative;
overflow: hidden;
width: 100%;
padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
}

/* Then style the iframe to fit in the container div with full height and width */
.responsive-iframe {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
}

class add active

1
2
3
4
5
6
7
8
9
10
11
12
13
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");

// If there's no active class
if (current.length > 0) {
current[0].className = current[0].className.replace(" active", "");
}

// Add the active class to the current/clicked button
this.className += " active";
});
}

Get Element in Iframe

1
2
3
var iframe = document.getElementById("myFrame");
var elmnt = iframe.contentWindow.document.getElementsByTagName("H1")[0];
elmnt.style.display = "none";

Media Queries with JavaScrip

1
2
3
4
5
6
7
8
9
10
11
function myFunction(x) {
if (x.matches) { // If media query matches
document.body.style.backgroundColor = "yellow";
} else {
document.body.style.backgroundColor = "pink";
}
}

var x = window.matchMedia("(max-width: 700px)")
myFunction(x) // Call listener function at run time
x.addListener(myFunction) // Attach listener function on state changes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<defs>
<linearGradient
id="grad1"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
>
<stop
offset="0%"
style="stop-color:#8095F0;stop-opacity:1"
/>
<stop
offset="100%"
style="stop-color:#51FCB5;stop-opacity:1"
/>
</linearGradient>
</defs>

1
2
3
4
5
6
'fill-color': ['interpolate-hcl', ['linear'], ['feature-state', 'population'], 0, 'red', 1e6, 'blue']


for (const district of districts) {
map.setFeatureState({ source: 'mysource', sourceLayer: 'mysourcelayer', id: district.id }, { population: district.population});
}
1
2
3
4
5
6
'fill-color': ['match', ['get', 'id'],
1020, 'red',
1033, 'green',
1038, 'red',
1049, 'white',
// ...
1
2
3
4
5
6
7
8
"icon-image": [
"case",
["all", ["==", ["get", "matched"], "True"], ["!=", ["get", "vehicle"], ["get", "standstill_vehicle"]]],
"orangemarker",
["==", ["get", "matched"], "True"],
"greenmarker",
"redmarker",
]
1
2
3
4
5
this.map.setPaintProperty("somelayer", "fill-color",
["case",
["==", ["get", "some_prop"], someval], "#34c0dd",
"#499bbc"
]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const layers = [{
id: 'countries',
type: 'fill',
source: 'countries',
paint: {
'fill-color': [
'match', ['get', 'filter_prop', ['global']],
'pop_est',
['step', ['get', 'pop_est'],
0, '#f8d5cc',
1000000, '#f4bfb6',
5000000, '#f1a8a5',
10000000, '#ee8f9a',
50000000, '#ec739b',
100000000, '#dd5ca8',
250000000, '#c44cc0',
500000000, '#9f43d7',
1000000000, '#6e40e6',
],
'gdp_md_est',
['step', ['get', 'gdp_md_est'],
0, '#f8d5cc',
1000, '#f4bfb6',
5000, '#f1a8a5',
10000, '#ee8f9a',
50000, '#ec739b',
100000, '#dd5ca8',
250000, '#c44cc0',
5000000, '#9f43d7',
10000000, '#6e40e6',
],
'#ffffff',
],
},
}];

以下这个未测试!

1
2
3
4
5
6
['step', ['zoom'],
['case', ['all', ['!', ['feature-state', 'hidden']], ['get', 'red'], 1, 0],
10,
['case', ['all', ['!', ['feature-state', 'hidden']], ['any', ['get', 'red'], ['get', 'green']], 1, 0],
15,
['case', [['!', ['feature-state', 'hidden']], 1, 0]],
1
2
3
4
5
6
7
8
9
10
11
12
13
14
map.addLayer({
id: "cluster-count",
type: "symbol",
source: "grundbuch",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
"text-size": 12
},
paint: {
"text-color": "#ffffff"
}
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"line-color": [
'case',
['boolean', ['feature-state', 'hover'], false],
'#c00',

[
'case',
['!=', ['get', 'color'], null],
['get', 'color'],
'#16e8e9'
]

],
````

###

test.map.showCollisionBoxes = true // 显示碰撞边界
test.map.showTileBoundaries = true // 显示tile边界
test.map.showOverdrawInspector = true

需要很习惯一段时间

### setFeatureState

if (quakeID) {
map.removeFeatureState({
source: “earthquakes”,
id: quakeID
});
}
map.setFeatureState({
source: ‘earthquakes’,
id: quakeID,
}, {
hover: true
});

1
2


map.addLayer({
‘id’: ‘earthquakes-viz’,
‘type’: ‘circle’,
‘source’: ‘earthquakes’,
‘paint’: {
// The feature-state dependent circle-radius expression will render
// the radius size according to its magnitude when
// a feature’s hover state is set to true
‘circle-radius’: [
‘case’,
[‘boolean’,
[‘feature-state’, ‘hover’],
false
],
[
‘interpolate’, [‘linear’],
[‘get’, ‘mag’],
1, 8,
1.5, 10,
2, 12,
2.5, 14,
3, 16,
3.5, 18,
4.5, 20,
6.5, 22,
8.5, 24,
10.5, 26
],
5
],
‘circle-stroke-color’: ‘#000’,
‘circle-stroke-width’: 1,
// The feature-state dependent circle-color expression will render
// the color according to its magnitude when
// a feature’s hover state is set to true
‘circle-color’: [
‘case’,
[‘boolean’,
[‘feature-state’, ‘hover’],
false
],
[
‘interpolate’, [‘linear’],
[‘get’, ‘mag’],
1, ‘#fff7ec’,
1.5, ‘#fee8c8’,
2, ‘#fdd49e’,
2.5, ‘#fdbb84’,
3, ‘#fc8d59’,
3.5, ‘#ef6548’,
4.5, ‘#d7301f’,
6.5, ‘#b30000’,
8.5, ‘#7f0000’,
10.5, ‘#000’
],
‘#000’
]
}
});

````

via https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/

examples

var aa = { “type”: “Polygon”,
“coordinates”: [
[
[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
]
}

var aa = { “type”: “Polygon”,
“coordinates”: [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ],
[ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ]
]
}

test.map.getSource(‘temp_line’).setData(aa)

{
type:’FeatureCollection’,
features:[
{
“geometry”: {
“type”: “MultiPoint”,
“coordinates”: [
[
108.91373500227928,
34.241324229728534
],
]
},
“type”: “Feature”,

}
]
}

1
Array.prototype.push.apply(a, [1,2]))

a.push(1, 2, 3);

1
2
3
4
var arr = [1];
var newItems = [2, 3];
arr.push(...newItems);
console.log(arr);

思路如下(console中有三个数据)

  • 后台请求(adss类型的)物理光缆 wlgl
  • 获得(界面中)铁路数据 railway
  • 计算 railway 和 wlgl 交叉点
  • groupBy 业务光缆,items push 所有点。然后去重为 items2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
console.log('Taking a break...');
await sleep(2000);
console.log('Two seconds later, showing sleep in a loop...');

// Sleep in loop
for (let i = 0; i < 5; i++) {
if (i === 3)
await sleep(2000);
console.log(i);
}
}

demo();

via https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep

layer chnage source

其实是重建

1
2
3
4
5
6
7
8
9
10
11
12
function setLayerSource (layerId, source, sourceLayer) {
const oldLayers = map.getStyle().layers;
const layerIndex = oldLayers.findIndex(l => l.id === layerId);
const layerDef = oldLayers[layerIndex];
const before = oldLayers[layerIndex + 1] && oldLayers[layerIndex + 1].id;
layerDef.source = source;
if (sourceLayer) {
layerDef['source-layer'] = sourceLayer;
}
map.removeLayer(layerId);
map.addLayer(layerDef, before);
}

https://github.com/mapbox/mapbox-gl-js/issues/1722

  • 为对象添加属性
  • 为对象添加方法
  • 浅克隆
  • 合并多个对象
  • 属性指定默认值
1
2
3
4
5
6
7
const DEFAULTS = {
logLevel: 0,
outputFormat: 'html'
};
function processContent(options) {
let options = Object.assign({}, DEFAULTS, options);
}

Object.create()、new Object()和{}的区别

直接字面量创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var objA = {};
objA.name = 'a';
objA.sayName = function() {
console.log(`My name is ${this.name} !`);
}
// var objA = {
// name: 'a',
// sayName: function() {
// console.log(`My name is ${this.name} !`);
// }
// }
objA.sayName();
console.log(objA.__proto__ === Object.prototype); // true
console.log(objA instanceof Object); // true

new关键字创建

1
2
3
4
5
6
7
8
9
var objB = new Object();
// var objB = Object();
objB.name = 'b';
objB.sayName = function() {
console.log(`My name is ${this.name} !`);
}
objB.sayName();
console.log(objB.__proto__ === Object.prototype); // true
console.log(objB instanceof Object); // true

Object.create 创建

一个完整的版本

https://ouyangresume.github.io/2019/12/19/mapbox%E7%9A%84Popup%E4%B8%8EVue%E6%A1%86%E6%9E%B6%E8%9E%8D%E5%90%88%E4%BD%BF%E7%94%A8/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import StarRating from 'vue-star-rating'

// ...

var starRating = new Vue({
...StarRating,
parent: this,
propsData: { /* pass props here*/ }
}).$mount()

starRating.$on('someEvent', (value) => {
// listen to events emitted from the component
})
var popup = new mapboxgl.Popup()
.setDOMContent(startRating.$el)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import InfoWindowContent from '../InfoWindowContent.vue'

L.popup({maxWidth: 600,
className: 'leaflet-info-window'})
.setLatLng(latlng)
.setContent('<div id="info-window"></div>')
.openOn(this.map)
const InfoWindow = Vue.extend(InfoWindowContent)
const infoWindow = new InfoWindow({
propsData: {
windowData: this.infoWindowData,
windowType: this.infoWindowType
},
store: this.$store
})
infoWindow.$mount("#info-window")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 添加Popup对象
const popup = new mapboxgl.Popup({
anchor: "bottom",
offset: offset || [1, -15],
className: "popup"
});
popup.on("close", function(p) {
if (p && p.target && p.target._vue) {
p.target._vue.$destroy();
}
});
const dom = document.createElement("div");
dom.className = "popup-content-wrapper";

popup.setLngLat(coordinates).setDOMContent(dom).addTo(map);
// 渲染局部Vue组件(mappopupwrapper)
popup._vue = new Vue({
render: h =>
h(MapPopupWrapper, {
props: {
width: "700px",
type: "resource",
target: {
feature
}
}
})
}).$mount(dom);

options.preserveDrawingBuffer

If true , the map’s canvas can be exported to a PNG using map.getCanvas().toDataURL() . This is false by default as a performance optimization.

1
map.getCanvas().toDataURL()

queryRenderedFeatures

Returns an array of GeoJSON Feature objects representing visible features that satisfy the query parameters.

https://docs.mapbox.com/mapbox-gl-js/api/map/#map#queryrenderedfeatures

1
2
3
4
5
// Find all features within a static bounding box
var features = map.queryRenderedFeatures(
[[10, 20], [30, 50]],
{ layers: ['my-layer-name'] }
);
1
2
3
4
5
6
7
// Find all features within a bounding box around a point
var width = 10;
var height = 20;
var features = map.queryRenderedFeatures([
[point.x - width / 2, point.y - height / 2],
[point.x + width / 2, point.y + height / 2]
], { layers: ['my-layer-name'] });
1
2
// Query all rendered features from a single layer
var features = map.queryRenderedFeatures({ layers: ['my-layer-name'] });

querySourceFeatures

Returns an array of GeoJSON Feature objects representing features within the specified vector tile or GeoJSON source that satisfy the query parameters.

https://docs.mapbox.com/mapbox-gl-js/api/map/#map#querysourcefeatures

1
2
3
4
// Find all features in one source layer in a vector source
var features = map.querySourceFeatures('your-source-id', {
sourceLayer: 'your-source-layer'
});

updateImage

1
2
3
// If an image with the ID 'cat' already exists in the style's sprite,
// replace that image with a new image, 'other-cat-icon.png'.
if (map.hasImage('cat')) map.updateImage('cat', './other-cat-icon.png');
1
2
3
4
5
6
7
8
"icon-color": [
"case",
["boolean", ["feature-state", "hover"], false],
"#F89806",
["boolean", ["==", ["get", "state"], 0], false],
"#2363F8",
["get", "color"]
],