当前位置:网站首页>Implementation principle of city selector component
Implementation principle of city selector component
2022-07-02 01:33:00 【Short and brilliant】
Requirements are as follows :
That's about it , Analysis is to make a city selection component , The function or requirement is to locate the current city 、 use localstorage Store the last located city and the recently selected city 、 You can filter out the city you want according to the input letters or words 、 Bringing data to the page is a problem of father son parameter transmission 、 Page using flex Layout .
I just made this component , The function of transferring parameters to the page has not been done , You can use parent-child components to pass parameters .
Knowledge points :
Briefly, let's talk about my city's selection components and some knowledge points :
1. backstage
I use node.js There is a background service , The use of express frame , It meets my needs . My data source is the city address of a website I crawled ( If infringement, please contact me to delete ), The data looks like this :
{
"id": 151,
"name": " Anshan ",
"pinyin": "anshan",
"acronym": "as",
"rank": "C",
"firstChar": "A"
}
I am here node The client called a location interface of a wave as my location service , And return the data to , When there is a problem with this interface or it is not obtained, it will return to Beijing . The specific code is :
// Get city data ,city Information crawled for me
app.get('/', function (req, res) {
res.send(city);
res.end()
});
// Call Sina's interface to return the location
app.get('/nowcity', function (req, res) {
let getIpInfo = function (cb) {
var url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json';
http.get(url, function (res) {
var code = res.statusCode;
if (code == 200) {
res.on('data', function (data) {
try {
cb(JSON.parse(data));
} catch (err) {
console.log(err)
}
});
}
}).on('error',function(e){
cb({
city: " Beijing ",
country: " China ",
province: " Beijing ",
})
})
};
getIpInfo(function (msg) {
let nowcity = msg
res.send(nowcity)
res.end()
})
});
2.vue The scaffold
This component is based on vue frame , I use vue-cli scaffolded , This piece of knowledge is not described , Refer to my blog 《vue Environment building and creating the first vuejs file 》.
3.stylus
This time I used css Preprocessor ——stylus.
stay vue-cli Use in stylus First, install dependencies npm install stylus --save-dev、
npm install stylus-loader --save-dev, Then use in the file
<style lang="stylus" scoped> that will do .
Introduce separate stylus Files use @import '~common/stylus/css.styl'.
4. The dependence of this project
In this project , In addition to installing the relevant stylus I also introduced better-scroll、fastclick、axios These three dependencies .
better-scroll It's the best library I've ever seen dealing with mobile scrolling , And the document is clear , Clear thinking .fastclick Used to handle mobile terminals click event 300 Millisecond delay . as for axios, I think everyone knows that ,axios It's based on promise Of HTTP library , Can be used in the browser and node.js in .
5.vue Use of components
In this project, I built 6 Functional components , They are the search box components 、 Search page component 、 Positioning assembly 、 Sidebar components 、 Pop up components 、 City display component . There are also two basic components , Rolling component and city component respectively .
The way to introduce City components is :
// Import file first
import Search from 'components/Search'
import Scroll from 'base/Scroll.vue'
import PositionBox from 'components/PositionBox'
import CityList from 'components/CityList'
import NavList from 'components/NavList'
import MaskBox from 'components/MaskBox'
import SearchList from 'components/SearchList'
// Then register in the parent component
components: {
'search': Search,
'scroll': Scroll,
'position-box': PositionBox,
'nav-list': NavList,
'city-list': CityList,
'mask-box': MaskBox,
'search-list': SearchList
}
// Use
<search @txtdata="searchText" :clearText="clearSearch"></search>
6. Parent child component parameters
It is very simple for a parent component to pass parameters to a child component , For the search box component : <search @txtdata="searchText" :clearText="clearSearch"></search>
When a parent component passes parameters to a child component, it only needs :clearText="clearSearch" that will do , among clearSearch For the information to be passed in ,clearText The name received for the subcomponent .
In the child component , Use props Attribute operation passes parameters :
props: {
clearText: Boolean
}
// With default parameters
props: {
clearText: {
type: Boolean,
default:false
}
}
The child component passes parameters to the parent component this.$emit The ginseng :
// Click on the list to trigger the event of changing the location
this.$emit('txtdata', this.searchText)
In the code above txtdata Is the name of the content passed to the parent component ,this.searchText Is the parameter . Use @ To trigger the receive event @txtdata="searchText":
// Search box content
searchText (text) {
// text That is, the passed parameters
}
7. Delayed operation
We are dealing with the front-end ajax Generally, we want to reduce interaction to improve performance and efficiency . In the search box component , We use the function of Lenovo search , Here I use regular implementation . So in the process of typing , We hope to interact after typing ( You can't let the browser always traverse the array or Ajax). Here I use a timing function to complete the delay effect :
if (this.timer) {
clearTimeout(this.timer) // Clear timer
}
this.timer = setTimeout(() => {
this.$emit('txtdata', this.searchText)
}, 300)
In this code , I'm bound to keyup event , in other words ,300 In milliseconds, as long as a button pops up , The event will be triggered to clear the last timer , Then regenerate the new timer ,300 If there is no input within milliseconds, the timer will trigger , Passing parameters to the parent component .
8. Regular
It used to be my biggest headache , Until one day I patiently read many documents and blogs .
export function getSearchList (text, list) {
let reg1 = /^\w+$/g // Detect whether it is a letter
let reg2 = new RegExp(`^${text}`, 'g') // Test template text
let reg3 = new RegExp('^[\\u4E00-\\u9FFF]{1,}$', 'g') // Detect whether it is Chinese
let resList = []
// When text When it's a letter
if (text.match(reg1)) {
for (let i = 0, len1 = list.length; i < len1; i++) {
for (let j = 0, len2 = list[i][1].length; j < len2; j++) {
// Filter those that meet this regularity
if (list[i][1][j].pinyin.match(reg2)) {
resList.push(list[i][1][j])
}
}
}
} else {
// ditto
if (reg3.test(text)) {
for (let i = 0, len1 = list.length; i < len1; i++) {
for (let j = 0, len2 = list[i][1].length; j < len2; j++) {
if (list[i][1][j].name.match(reg2)) {
resList.push(list[i][1][j])
}
}
}
}
}
return resList
}
JavaScript Through built-in objects RegExp
regular expression , There are two ways to create regular expression objects , Constructors, respectively var reg=new RegExp('<%[^%>]+%>','g') and
Literal var reg=/<%[^%>]%>/g
, Because I used template statements this time , Constructor is used ,
final g On behalf of the whole .
// Match a character , This character can be 0-9 Any one of
var reg1 = /[0123456789]/
// Match a character , This character can be 0-9 Any one of
var reg2 = /[0-9]/
// Match a character , This character can be a-z Any one of
var reg3 = /[a-z]/
// Match a character , This character can be a capital letter 、 Lowercase letters 、 Any one of the numbers
var reg3 = /[a-zA-Z0-9]/
// Match a character , This character can be any one of Chinese characters
var reg4 = /[\\u4E00-\\u9FFF]/
We can also introduce restrictions at the beginning and end :
^ | With xxx start |
$ | With xxx ending |
\b | Word boundaries |
\B | Non word boundary |
Quantitative quantifier :
character | meaning |
---|---|
? | Zero or one occurrence ( Once at most ) |
+ | One or more times ( At least once ) |
* | Zero or more times ( Any time ) |
{n} | appear n Time |
{n,m} | appear n To m Time |
{n,} | At least appear n Time |
9.this.$refs
In general , obtain DOM Elements , Need to be document.querySelector(".input1") Access to this dom node , And then get input1 Value . But with ref After binding , We don't need to get dom The node , Directly above input The binding input1, then $refs Just call it inside . And then in javascript It's called like this :this.$refs.input1 This can reduce access to dom Node consumption .
<div ref="wrapper" class="scroll">
</div>
// here this.$refs('wrapper') That's what it stands for div
10.slot
Understand literally ,slot by “ slot , Ditch ”, It's probably a placement component or dom Where the structure . Subcomponent templates must Contains at least one <slot>
jack , Otherwise, the contents of the parent component will be discarded . When the subcomponent template has only one slot without attributes , The entire content fragment passed in by the parent component will be inserted into the slot DOM Location , And replace the slot label itself . Initially in <slot>
Anything in the tag is considered as an alternative . The alternate content is compiled within the scope of the subcomponent , And only when the host element is empty , And there is no content to insert .
Assume my-component
The components have the following templates :
<div>
<h2> I'm the title of the subcomponent </h2>
<slot>
Only if there is no content to distribute .
</slot>
</div>
Parent component template :
<div>
<h1> I am the title of the parent component </h1>
<my-component>
<p> This is some of the initial content </p>
<p> This is more of the initial content </p>
</my-component>
</div>
Render the result :
<div>
<h1> I am the title of the parent component </h1>
<div>
<h2> I'm the title of the subcomponent </h2>
<p> This is some of the initial content </p>
<p> This is more of the initial content </p>
</div>
</div>
Slot of this project :
<!-- Parent component -->
<scroll :data="citylist" ref="suggest" :probeType="3" :listenScroll="true" @distance="distance" @scrollStore="scrollStore">
<div>
<position-box :chooseCity="chooseCity" :orientate="nowCity" :historyCityArr="historyCityArr" @changeCity="changeCity"></position-box>
<city-list :citylist="citylist" :elementIndex="elementIndex" @positionCity="changeCity" @singleLetter="singleLetter"></city-list>
</div>
</scroll>
<!-- Child components -->
<div ref="wrapper" class="scroll">
<slot></slot>
</div>
11.better-scroll Use
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
scrollY: true, // The rolling direction is Y Axis
click: true, // Whether to distribute click event , It is usually judged that the browser distributes click still betterscroll Distributed click, It can be used event._constructed, if bs The distribution is true
momentum: true, // Whether to turn on sliding inertia when sliding fast
bounce: false, // Whether to enable springback animation
bounceTime: 700, // The number of milliseconds the stretch animation lasts
deceleration: 0.001, // The greater the rolling momentum, the faster the deceleration , It is suggested that no more than 0.01
momentumLimitTime: 300, // According to the maximum time of inertia drag
momentumLimitDistance: 15, // Minimum drag distance in accordance with inertial drag
resizePolling: 60 // When the window is resized , Recalculate better-scroll Time interval of
})
By building a scroll Object to use better-scroll, There must be a dom node , namely this.$refs.wrapper. Add some attributes to define .
In this project , We used Bscroll Three methods of :
refresh()
Parameters : nothing
Return value : nothing
effect : Recalculate better-scroll, When DOM When the structure changes, it is necessary to call to ensure the normal effect of scrolling .
scrollTo(x, y, time, easing)
Parameters : Return value : nothing
{Number} x Horizontal axis coordinates ( Company px)
{Number} y Vertical coordinates ( Company px)
{Number} time How long the scrolling animation takes to execute ( Company ms)
{Object} easing Slow motion function , Generally, modification is not recommended , If you want to modify , Refer to... In the source code ease.js Li's way of writing
effect : Scroll to the specified location
scrollToElement(el, time, offsetX, offsetY, easing)
Parameters : Return value : nothing
{DOM | String} el Scroll to the target element , If it's a string , The internal will try to call querySelector convert to DOM object .( I used this.$refs)
{Number} time How long the scrolling animation takes to execute ( Company ms)
{Number | Boolean} offsetX Offset from the horizontal axis of the target element , If set to true, Then roll to the center of the target element
{Number | Boolean} offsetY Offset from the vertical axis of the target element , If set to true, Then roll to the center of the target element
{Object} easing Slow motion function , Generally, modification is not recommended , If you want to modify , Refer to... In the source code ease.js Li's way of writing
effect : Scroll to the specified target element .
12.localstorage
I believe everyone is right localstorage and sessionstorage The difference between has been understood , The biggest difference is localstorage image ROM, and sessionstorage image RAM.
In this project , adopt setItem and getItem To operate localstorage:
localStorage.setItem('historyCityArr', arr)
localStorage.getItem('historyCityArr')
13. transition transition
It is similar to adding an animation effect when rendering and removing units .
<transition name="flag">
<div class="nowFlag" v-if="flag">{
{flagText}}</div>
</transition>
.flag-leave-active
transition all 1s
.flag-leave-to
opacity 0
The explanation of paragraph to is , Add a leave ( remove ) The transition of , The opacity is determined by 1 become 0.
14.stop&prevent
Call in event handler event.preventDefault()
or event.stopPropagation()
It's a very common requirement . Although we can easily implement this in the method , But the better way is : Method has only pure data logic , Instead of dealing with DOM Details of the incident . To solve this problem ,Vue.js by v-on
Provides event modifiers . I mentioned before , The modifier is represented by the instruction suffix at the beginning of the dot .
.stop Stop the event from bubbling
.prevent Block default events
.capture Prevent event capture
.once Trigger only once
Business part :
1. Search box components
html The code is as follows : The parent component passes the information of whether to empty the content to the child component ( Used to change the search page after clicking the search page option ), Subcomponent trigger keyup Pass the content to be searched to the parent component when the event occurs .
<!-- Parent component -->
<search @txtdata="searchText" :clearText="clearSearch"></search>
<!-- Child components -->
<div class="search-box">
<div class="ipt-box">
<input type="text" class="ipt" placeholder=" The city name / pinyin " @keydown="entry()" v-model="searchText" />
<div class="icon-box">
<i class="iconfont icon-sousuo icon"></i>
</div>
</div>
</div>
// Child components js
methods: {
// Delay search
entry () {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
this.$emit('txtdata', this.searchText)
}, 300)
}
},
watch: {
// Clear the search
clearText (val) {
if (val) {
this.searchText = ''
this.entry()
}
}
}
There is an effect of reducing interaction and computation when passing up , Realized by timer , As mentioned above .
2. Positioning assembly
<!-- Parent component module -->
<position-box :chooseCity="chooseCity" :orientate="nowCity" :historyCityArr="historyCityArr" @changeCity="changeCity"></position-box>
<!-- Sub component modules -->
<div class="position-box">
<div class="choose">
<span> You have chosen :{
{chooseCity}}</span>
</div>
<div class="hostory">
<p> location / Recently visited </p>
<div class="citybox">
<button @click="changeCity(orientate)">
<i class="iconfont icon-dingwei icon"></i>{
{orientate}}
</button>
<button @click="changeCity(item)" v-for="item in historyCityArr" :key="item">{
{item}}</button>
</div>
</div>
<div class="hot">
<p> Hot City </p>
<div class="citybox">
<button v-for="city in hotCitys" :key="city" @click="changeCity(city)">{
{city}}</button>
</div>
</div>
</div>
In this part , Two events will be triggered when the page is loaded at the beginning : Locate and read localstorage The history view records stored inside .
axios.get('http://localhost:1234/nowcity').then((res) => {
this.nowCity = res.data.city
if (!this.choiceCity && !this.choiceCityName) {
this.choiceCity = this.nowCity
this.choiceCityName = this.nowCity
}
}, () => {
this.nowCity = ' Beijing '
if (!this.choiceCity && !this.choiceCityName) {
this.choiceCity = this.nowCity
this.choiceCityName = this.nowCity
}
})
The logic of the positioning part is simple , Nothing more than getting data , If you can't get it, the default is Beijing .
localstorage The data processing of is in this component :
setHistory (arr) {
localStorage.setItem('historyCityArr', arr)
},
// Get it locally
getHistory () {
let history = localStorage.getItem('historyCityArr')
if (!history) {
this.historyCityArr = []
} else {
this.historyCityArr = history.split(',')
}
},
// Save locally , City being viewed
setCity (name) {
localStorage.setItem('seeCity', name)
},
// Get it locally ,, City being viewed
getCity () {
let name = localStorage.getItem('seeCity')
if (!name) {
this.choiceCity = ''
this.choiceCityName = ''
} else {
this.choiceCity = name
this.choiceCityName = name
}
}
When the city changes , Out trigger two setItem event ( Whether storing arrays or strings ), So that when opened here getItem Data can be obtained . When you first load the page , Will send two get event , After obtaining the data, it is transferred to the rendering data in the positioning module .get The information obtained is a string , After we get it, we need to convert it into an array .
3. Page city component
<!-- Parent component module -->
<city-list :citylist="citylist" :elementIndex="elementIndex" @positionCity="changeCity" @singleLetter="singleLetter"></city-list>
<!-- Sub component modules -->
<div class="lists">
<div v-for="citys in citylist" :key="citys[0]" :dataNum="citys[1].length">
<p class="city-title" :ref="citys[0]">{
{citys[0]}}</p>
<p class="city-item" v-for="city in citys[1]" :key="city.id" @click="changeCity(city.name)">{
{city.name}}</p>
</div>
</div>
Just talking about this component , It belongs to the very simple kind , It only has the function of displaying the rendering information and clicking the city option to transfer the city information value upward . But the right sidebar is added behind nav After that, upward transmission was added dom Function of node :
// Parent component
singleLetter (dom) {
this.$refs.suggest.scrollToElement(dom, 200, false, false)
}
// Child components
elementIndex (val) {
if (val === ' The top ') {
return false
}
this.$emit('singleLetter', this.$refs[val][0])
}
The parent component gets the city uploaded by the city component dom Triggered after node information Bscroll Of scrollToElement Method ,0.2 Scroll to the corresponding position within seconds .
4. Pop up components
This component is after clicking to select a city ( And the city clicked is not the city that has been viewed at present ) Trigger .
<!-- Parent component module -->
<mask-box v-if="maskShow" :message="maskMessage" @chooseing="chooseResult"></mask-box>
<!-- Sub component modules -->
<div class="mask-box">
<div class="mask-body"></div>
<div class="btn-box">
<div class="message">
<p>{
{message}}</p>
</div>
<div class="btn-left" @click="chooseTrue()">
<p> determine </p>
</div>
<div class="btn-right" @click="chooseFalse()">
<p> Cancel </p>
</div>
</div>
</div>
js The part is very simple
chooseTrue () {
this.$emit('chooseing', true)
},
chooseFalse () {
this.$emit('chooseing', false)
}
Upload values according to the different buttons clicked . When the value is true Trigger an event of the parent component , Scroll the page to the top .
// Confirm switching positioning
chooseResult (res) {
if (!res) {
this.maskClose() // Don't switch , Only close the pop-up window
} else {
this.choiceCityName = this.choiceCity
this.local()
this.associationShow = false // Close the search box ( In search mode )
this.clearSearch = true // Clear the words in the input box ( In search mode )
// Scroll to the top after confirmation
this.$refs.suggest.scrollTo(0, 0, 200)
this.maskClose()
}
}
5. Search list component
The code of this component page is nothing more than , The logic code is also relatively simple , Using the above regular , Not much explanation .
<!-- Parent component module -->
<transition name="list">
<search-list v-if="associationShow" :searchListContent="searchListContent" @changeName="changeCity"></search-list>
</transition>
<!-- Sub component modules -->
<div class="listbody">
<scroll :data="searchListContent">
<div>
<city-item :searchListContent="searchListContent" @changeName="changeCity"></city-item>
</div>
</scroll>
</div>
The component is only for display and click to select a city , Function and 3 The components are the same , But no Bscroll The rolling Events .
6. Right sidebar nav Components
<!-- Parent component module -->
<nav-list :navList="cityIndexList" @toElement="toElement" :flagText="flagText"></nav-list>
<!-- Sub component modules -->
<div class="navbody">
<div class="navList" @touchstart.stop.prevent="start" @touchmove.stop.prevent="move">
<div :class="navClass(item)" :data-name="item" v-for="item in navList" :key="item">
{
{item}}
</div>
< /div>
</div>
This part html Less code , But the interaction with other components is the most , For example, click on nav The letter on the page scrolls the city component to the corresponding position 、 Slide on it to realize the continuous scrolling of the page city component .
Click on nav The letter on the page scrolls the city component to the corresponding position , Click to trigger touchstart This event :
start (e) {
let item = handleDomData(e.target, 'data-name')
this.touch.start = e.touches[0].pageY
this.touch.startIndex = getIndex(this.navList, item)
this.scrollToElement(item)
}
Record the position of the first click to provide the height of the starting point for future sliding , And trigger scrollToElement event , Up by value , Let the parent component scroll Scroll to the corresponding position .
The function of continuous scrolling of the city component on the page is realized in , Trigger touchmove This event :
move (e) {
this.touch.end = e.touches[0].pageY
let distance = this.touch.end - this.touch.start
this.touch.endIndex = Math.min(Math.max(this.touch.startIndex + Math.floor((distance + 10) / 20), 0), 22)
this.scrollToElement(this.navList[this.touch.endIndex])
}
Calculate the current letter by the distance in the rolling process , And upload the changed letters , Let the parent component scroll Scroll to the corresponding position .
In this component , We introduced two js function , Namely start Medium handleDomData and getIndex
// Get or give dom Attribute assignment
export function handleDomData (el, name, val) {
if (val) {
return el.setAttribute(name, val)
} else {
return el.getAttribute(name)
}
}
// Get the corresponding of each letter in the array index
export function getIndex (arr, query) {
let key
arr.map((val, index) => {
if (val === query) {
key = index
return false
}
})
return key
}
7.( Non component ) Letter display card
This little thing is not a component , But it has certain functions , So I put it here . The code is super simple , Accept two parameters , Whether to display and what to display :
<transition name="flag">
<div class="nowFlag" v-if="flag">{
{flagText}}</div>
</transition>
Whether to display this parameter from scroll Three events of the basic component :
// monitor scroll event
if (this.listenScroll) {
// Trigger at the beginning of scrolling
this.scroll.on('scrollStart', () => {
this.$emit('scrollStore', true)
})
// pos For position parameters
this.scroll.on('scroll', (pos) => {
this.$emit('distance', Math.abs(pos.y))
this.$emit('scrollStore', true)
})
// Roll over
this.scroll.on('scrollEnd', () => {
this.$emit('scrollStore', false)
})
}
this.listenScroll We do not call this parameter on the search list , So the default is false, Only on the main page true. Monitor when triggered scroll Activity of components , For example, upload when scrolling starts true, Rolling middle pass true, End time transmission false To control the display and hiding of cards .
The words on the card are calculated according to the distance scrolled :
// Display the words on the alphabet according to the sliding distance
distance (val) {
for (let i = 0, len = this.arrHeight.length; i < len; i++) {
if (val < this.arrHeight[i]) {
this.flagText = this.cityIndexList[i]
return false
}
}
}
// Height array source
// Calculate the height of each part of the link
export function getDistance (arr) {
let titleHeight = 30
let itemHeight = 35
let distanceArr = []
arr.map((item) => {
distanceArr.push(titleHeight + itemHeight * item[1].length)
})
return distanceArr
}
In addition to being used in this card, the obtained letters will also be passed in navList In the component , Realize the difference of the current letter style .
End ~
边栏推荐
- GL Studio 5 installation and experience
- About asp Net core uses a small detail of datetime date type parameter
- Raspberry pie 4B learning notes - IO communication (1-wire)
- Learn C language from scratch day 025 (maze)
- 卷積神經網絡(包含代碼與相應圖解)
- CEPH buffer yyds dry inventory
- 站在新的角度来看待产业互联网,并且去寻求产业互联网的正确方式和方法
- 企业应该选择无服务器计算吗?
- Brief description of grafana of # yyds dry goods inventory # Prometheus
- Variables and constants of go language foundation
猜你喜欢
SAP ui5 beginner tutorial XXI - trial version of custom formatter of SAP ui5
How to compress video size while adding watermark with one click?
6-3 vulnerability exploitation SSH environment construction
开发那些事儿:如何利用Go单例模式保障流媒体高并发的安全性?
Finally got byte offer, 25-year-old inexperienced experience in software testing, to share with you
Matlab uses audioread and sound to read and play WAV files
[Obsidian] wechat is sent to Obsidian using remotely save S3 compatibility
微信小程序中使用tabBar
Android: how can golden nine and silver ten squeeze into the first-line big factories from small and medium-sized enterprises? The depth of interview questions in large factories
[image enhancement] vascular image enhancement based on frangi filter with matlab code
随机推荐
电子协会 C语言 1级 33 、奇偶数判断
Circular statements in shell programming
error: . repo/manifests/: contains uncommitted changes
Finally got byte offer, 25-year-old inexperienced experience in software testing, to share with you
并发编程的三大核心问题
Edge extraction edges based on Halcon learning_ image. Hdev routine
企业应该选择无服务器计算吗?
MySQL application day02
Shell Function
Leetcode, 3 repeatless longest subsequence
笔者更加愿意将产业互联网看成是一个比消费互联网要丰富得多的概念
Memorabilia of domestic database in June 2022
6-3 vulnerability exploitation SSH environment construction
969 interlaced string
Datawhale community blackboard newspaper (issue 1)
Day 13 of hcip (relevant contents of BGP agreement)
Leetcode 45 Jumping game II (2022.02.14)
Variables and constants of go language foundation
学习笔记2--高精度地图定义及价值
Exclusive delivery of secret script move disassembly (the first time)