所謂的兄弟組件之間的聯(lián)動,其實就是實現(xiàn)點擊右側(cè)的字母就能跳轉(zhuǎn)至對應(yīng)的首字母城市,因此列表組件需要知道右側(cè)的字母列表的點擊事件所對應(yīng)的元素字母,這就需要兄弟組件間的數(shù)據(jù)傳遞了(Alphabet組件與List組件之間的通信),可以使用到中央數(shù)據(jù)總線Bus,但是由于這里的業(yè)務(wù)邏輯不是很復(fù)雜,因此可以將Alphabet組件內(nèi)的信息傳遞到City組件(子組件向父組件傳遞信息,發(fā)布訂閱模式),然后City組件向List組件傳遞信息(父組件向子組件傳遞信息,屬性傳值方式)。
在gitee的分支欄點擊新建分支city-components,然后記得將本地master分支切換到city-components分支。
打開Alphabet.vue文件,給字母表中的字母添加一個click事件,然后嘗試將點擊的字母在控制臺上進行輸出顯示:
<template>
<ul class="list">
<li class="item"
v-for="(item,key) of cities"
:key="key"
@click="handleLetterClick"
>
{{key}}
</li>
</ul>
</template>
然后在script標簽添加這個handleLetterClick方法:
methods: {
handleLetterClick (e) {
console.log(e.target.innerText)
}
}
可以測試一下當你點擊右側(cè)列表中的字母,控制臺是否真的輸出了對應(yīng)的字母:
前面說了由于這里的業(yè)務(wù)邏輯不是很復(fù)雜,因此可以將Alphabet組件內(nèi)的信息傳遞到City組件(子組件向父組件傳遞信息,發(fā)布訂閱模式),然后City組件向List組件傳遞信息(父組件向子組件傳遞信息,屬性傳值方式)。
那就開始編寫使用發(fā)布訂閱模式實現(xiàn)Alphabet組件內(nèi)的信息傳遞到City組件的代碼。修改子組件Alphabet.vue中handleLetterClick函數(shù)代碼為:
methods: {
handleLetterClick (e) {
/** 注意此處必須使用innerText而不是innerHTML **/
this.$emit('change', e.target.innerText)
}
}
接著去父組件City.vue中監(jiān)聽該chang事件,請定義相應(yīng)的handleLetterChange去接收子組件傳遞過來的信息:
<template>
<div>
<city-header></city-header>
<city-search></city-search>
<city-list :cities="cities" :hotCities="hotCities"></city-list>
<city-alphabet :cities="cities" @change="handleLetterChange"></city-alphabet>
</div>
</template>
handleLetterChange (letter) {
console.log(letter)
}
控制臺測試發(fā)現(xiàn)當你點擊右側(cè)列表中的字母,控制臺仍然輸出了對應(yīng)的字母。接下來就是父組件City.vue通過屬性傳值的方式將數(shù)據(jù)傳遞給子組件List.vue。修改父組件City.vue中handleLetterChange函數(shù)代碼為:
handleLetterChange (letter) {
this.letter=letter
}
然后在父組件中的data中返回letter,并將其通過屬性傳值給city-list組件:
<template>
<div>
...
<city-list :cities="cities" :hotCities="hotCities" :letter="letter"></city-list>
...
</div>
</template>
data () {
return {
...
letter: ''
}
然后在子組件List.vue中通過props來接收數(shù)據(jù):
props: {
cities: Object,
hotCities: Array,
letter: String
},
當List.vue發(fā)現(xiàn)letter有變化的時候,就顯示跟letter首字母相同的城市列表,這種功能可以通過偵聽器來實現(xiàn):
watch: {
letter () {
console.log(this.letter)
}
}
控制臺測試發(fā)現(xiàn)當你點擊右側(cè)列表中的字母,控制臺仍然輸出了對應(yīng)的字母。
還記得之前推薦的那篇關(guān)于better-scroll的文章:當 better-scroll 遇見 Vue么,里面介紹了如何滾動至某個元素。既然是滾動至某個元素,那么肯定需要選擇某個DOM節(jié)點了,Vue提供了ref來選擇節(jié)點(List.vue):
<template>
<div class="area"
v-for="(item, key) of cities"
:key="key"
:ref="key"
>
</template>
然后使用偵聽器來監(jiān)聽letter的變化:
watch: {
letter () {
if (this.letter) {
console.log(this.$refs[this.letter])
}
}
}
當你點擊某個字母時,控制臺輸出:
而這個索引為0的div.area區(qū)域中包含了我們所需要的的城市列表信息:
既然這樣就可以直接獲取到對應(yīng)的DOM節(jié)點,并將該節(jié)點傳遞給better-scroll,里面有一個scrollToElement方法,之后就能實現(xiàn)點擊某個字母,城市列表頁就會顯示對應(yīng)的城市信息:
watch: {
letter () {
if (this.letter) {
const element=this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
}
}
}
前面介紹的是點擊右側(cè)的字母就能跳轉(zhuǎn)至對應(yīng)的首字母城市,其實比這個更普通的 就是當你拇指按住字母表上下滑動時,左邊List組件也會相應(yīng)的上下跳動。
實現(xiàn)這個需要,首先我們要監(jiān)聽使用者的手指,記錄時候開始點擊字母列表(touchstart),什么時候開始滾動(touchmove),以及什么時候離開字母列表(touchend)等等,自然而然地想到使用事件監(jiān)聽。注意我們還需要定義一個標志狀態(tài)(touchStatus),默認為flase,只有當你手指觸摸的時候才會變成true,其實就是指定這三個函數(shù)的執(zhí)行順序:
<template>
<ul class="list">
<li class="item"
v-for="(item,key) of cities"
:key="key"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
{{key}}
</li>
</ul>
</template>
<script>
...
methods: {
handleLetterClick (e) {
...
handleTouchStart () {
this.touchStatus=true
},
handleTouchMove () {
if (this.touchStatus) {
}
},
handleTouchEnd () {
this.touchStatus=false
}
}
}
</script>
現(xiàn)在我們需要知道當你拇指在滑動的時候,你的拇指停留在哪個字母上,這件事情其實是較為復(fù)雜的,可以提供一種思路僅供參考:先獲取A字母距離頂部的高度,然后當你滑動的時候獲取你當前字母距離頂部的高度,接著將后者減去前者得到一個差值,最后用這個差值除于每個字母的長度就能得到這是第幾個字母。然后讓該字母觸發(fā)對應(yīng)的事件即可,那么這樣你需要新建一個數(shù)組用于存放字母,然后根據(jù)索引來獲取字母,可以使用計算屬性:
computed: {
letters () {
const letters=[]
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
上面的計算屬性其實就是得到一個類似于['A','B','C','D']的數(shù)組。然后你城市字母表遍歷的對象就不再是cities,而是letters了(那就不需要使用key了,直接遍歷輸出item就可以):
<template>
<ul class="list">
<li class="item"
v-for="item of letters"
:key="item"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
{{item}}
</li>
</ul>
</template>
接下來繼續(xù)編寫handleTouchMove函數(shù)的內(nèi)容,這個函數(shù)就是用于計算當你拇指在滑動的時候,你的拇指停留在哪個字母上。實現(xiàn)的邏輯是先獲取A字母距離頂部的高度,然后當你滑動的時候獲取你當前字母距離頂部的高度,接著將后者減去前者得到一個差值,最后用這個差值除于每個字母的長度就能得到這是第幾個字母。
第一步在template中給DOM節(jié)點添加ref屬性,用于獲取某個DOM節(jié)點:ref="item";
第二步,修改handleTouchMove函數(shù)為:
handleTouchMove () {
if (this.touchStatus) {
const startY=this.$refs['A'][0].offsetTop
console.log(startY)
}
},
通過測試發(fā)現(xiàn)當你拇指在滑動的時候,控制臺始終輸出61,這個61就是A字母距離頁面頂部(注意是藍色區(qū)域底部)的高度:
然后就可以獲取每個字母距離整個頁面的高度,里面有一個最小的值就是拇指距離整個頁面最小的高度:
如果你想要獲取某個字母距離藍色區(qū)域底部的高度,可以將其高度減去藍色區(qū)域底部的高度79(43(Header組件高度)+36(Search組件告高度)=79),然后除以20(每個字母高度)并向下取整就能得到每個字母的索引:
handleTouchMove (e) {
if (this.touchStatus) {
const startY=this.$refs['A'][0].offsetTop
const touchY=e.touches[0].clientY - 79
const index=Math.floor((touchY - startY) / 20)
console.log(index)
}
},
測試發(fā)現(xiàn)拇指移動到字母M處,右側(cè)顯示正常:
最后使用子組件Alphabet使用發(fā)布訂閱模式向City組件傳遞數(shù)據(jù):
handleTouchMove (e) {
if (this.touchStatus) {
const startY=this.$refs['A'][0].offsetTop
const touchY=e.touches[0].clientY - 79
const index=Math.floor((touchY - startY) / 20)
if (index >=0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}
},
測試發(fā)現(xiàn)功能顯示正常。
接下來就是對上面的代碼進行優(yōu)化,因為startY是一個定值,而按照目前寫的代碼則是每次都需要去執(zhí)行,這會造成性能低下。可以在data中return一個startY(初始值為0),然后定義一個生命周期函數(shù)update,只有頁面的數(shù)據(jù)被更新同時頁面完成了渲染時,該方法才會被執(zhí)行:
data () {
return {
touchStatus: false,
startY: 0
}
},
updated () {
this.startY=this.$refs['A'][0].offsetTop
},
handleTouchMove (e) {
if (this.touchStatus) {
const touchY=e.touches[0].clientY - 79
const index=Math.floor((touchY - this.startY) / 20)
if (index >=0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}
},
我們知道頁面一開始的時候cities變量是空值,也就是Alphabet組件內(nèi)不會顯示任何信息,然后通過ajax獲取到數(shù)據(jù)時Alphabet組才會被重新渲染,之后會觸發(fā)生命周期函數(shù)updated,這時候開始計算藍色區(qū)域底部與字母A標簽的距離。
還有一個優(yōu)化就是函數(shù)節(jié)流。函數(shù)節(jié)流就是限制一個函數(shù)在一定時間內(nèi)只能執(zhí)行一次,這里就是當你拇指在字母表中上下移動時,touchmove函數(shù)執(zhí)行的頻率非常高會造成性能低下,因此可以借助于函數(shù)節(jié)流來優(yōu)化該代碼。具體的函數(shù)節(jié)流介紹可以參看這篇文章JS進階篇1---函數(shù)節(jié)流(throttle),此處采用計時器規(guī)定在一定時間內(nèi)函數(shù)才允許執(zhí)行。打開Alphabet.vue文件,先return一個timer對象,初始值是null,其次修改handleTouchMove函數(shù)代碼為:
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer=setInterval(()=> {
const touchY=e.touches[0].clientY - 79
const index=Math.floor((touchY - this.startY) / 20)
if (index >=0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}, 16)
}
},
原理非常簡單,先判斷timer計時器對象是否存在,存在就清空該計時器避免緩存,否則就定義一個計時器并設(shè)置計時器時間為16毫秒,即每16毫秒才計算一次,這樣可避免不必要的計算工作。
在gitee的分支欄點擊新建分支city-search-logic,然后記得將本地master分支切換到city-search-logic分支,接下來開始進行搜索框的業(yè)務(wù)邏輯開發(fā)。
打開city文件夾中的Search.vue組件,修改其中的template代碼為:
<template>
<div>
<div class="search">
<input class="search-input" type="text" placeholder="輸入城市名稱或者拼音"/>
</div>
<div class="search-content">
<ul>
<li>123</li>
</ul>
</div>
</div>
</template>
這里面其實就是新增了一個搜索結(jié)果展示的區(qū)域,也就是.search-content類所占區(qū)域,接著在style標簽中新增.search-content類所對應(yīng)的樣式(注意它應(yīng)該和.search類是平級關(guān)系):
.search-content
z-index: 1
overflow: hidden
position: absolute
top: 1.58rem
left: 0
right: 0
bottom: 0
background: green
然后需要實現(xiàn)搜索信息與結(jié)果展示區(qū)域的聯(lián)動,就需要使用到數(shù)據(jù)的雙向綁定:
<script>
export default {
name: 'CitySearch',
data () {
return {
keyword: ''
}
}
}
</script>
<template>
<div>
<div class="search">
<input v-model="keyword" class="search-input" type="text" placeholder="輸入城市名稱或者拼音"/>
</div>
...
</div>
</template>
最后結(jié)果肯定是顯示城市,那么需要從父組件City中接收cities,修改City.vue組件中的template代碼為:
<template>
<div>
<city-header></city-header>
<city-search :cities="cities"></city-search>
....
</div>
</template>
然后在子組件Search.vue中通過props來接收cities:
props: {
cities: Object
},
然后我們在子組件Search.vue中return一個數(shù)組list(該數(shù)組用于存儲搜索結(jié)果)和計時器timer(函數(shù)節(jié)流使用):
data () {
return {
keyword: '',
list: [],
timer: null
}
}
接著我們定義一個偵聽器用于監(jiān)聽keyword的變化:
watch: {
keyword () {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer=setInterval(()=> {
// 書寫在cities對象中查找某個元素的邏輯
const result=[]
for (let i in this.cities) {
// i就是字母A,B...,而this.city[i]就是數(shù)組,value就是數(shù)組中的每一項
this.cities[i].forEach((value)=> {
if (value.spell.indexOf(this.keyword) > -1 ||
value.name.indexOf(this.keyword) > -1
) {
result.push(value)
}
})
}
this.list=result
}, 100)
}
}
在city.json文件中,我們定義的cities結(jié)構(gòu)為:
"cities": {
"A": [{
"id": 56,
"spell": "aba",
"name": "阿壩"
}, {
"id": 57,
"spell": "akesu",
"name": "阿克蘇"
}...
也就是cities本身是一個對象,里面又包含了一個數(shù)組作為值,而數(shù)組中包含的則是一個個對象。注意if語句中的判斷條件為value.spell.indexOf(this.keyword) > -1 ||value.name.indexOf(this.keyword) > -1`也就是通過拼音或中文都可以查找是否能找到匹配的數(shù)據(jù)。
接下來就是對搜索結(jié)果的布局進行優(yōu)化,給搜索結(jié)果添加一個.search-item類和一個邊框類.border-bottom:
<div class="search-content">
<ul>
<li class="search-item" v-for="item of list" :key="item.id">{{ item.name }}</li>
</ul>
</div>
然后給.search-item類添加樣式,并修改.search-content類的背景顏色為#eee:
.search-content
z-index: 1
overflow: hidden
position: absolute
top: 1.58rem
left: 0
right: 0
bottom: 0
background: #eee
.search-item
line-height: .62rem
padding-left: .2rem
background: #fff
color: #666
測試發(fā)現(xiàn)頁面顯示正常,但是搜索結(jié)果是無法滾動的,此時可以借助于bertter-scroll來實現(xiàn)。
第一步獲取到search-content類節(jié)點DOM:
<div class="search-content" ref="search">
<ul>
<li class="search-item border-bottom" v-for="item of list" :key="item.id">{{ item.name }}</li>
</ul>
</div>
第二步導(dǎo)入Bscroll類及創(chuàng)建該對象:
<script>
import BScroll from 'better-scroll'
export default {
name: 'CitySearch',
props: {
cities: Object
},
mounted () {
this.scroll=new BScroll(this.$refs.search)
}
}
</script>
只需這兩步就完成了頁面滾動的效果。還有一個問題就是當你輸入完并清空搜索框的時候,搜索結(jié)果依舊還是存在:
其實只需要當你的keyword為空的時候,你將這個list設(shè)置為[]即可,在偵聽器中添加實現(xiàn)上述功能的邏輯:
watch: {
keyword () {
if (this.timer) {
clearTimeout(this.timer)
}
if (!this.keyword) {
this.list=[]
return
}
...
}
這樣就解決了這個問題。新的問題又來了就是當你輸入一串非常長的字母或者說是輸入的關(guān)鍵詞不能匹配任何城市時,前面我們是什么也不顯示,其實這個是有一點問題的,我們最好是在頁面上添加諸如“找不到對應(yīng)的城市”等信息。最簡單的方式就是使用v-show來進行顯示:
<div class="search-content" ref="search">
<ul>
<li class="search-item border-bottom" v-for="item of list" :key="item.id">{{ item.name }}</li>
</ul>
<ul>
<li class="search-item border-bottom" v-show="!list.length">沒有找到匹配的城市</li>
</ul>
</div>
這樣我們就實現(xiàn)了當list的長度為0的時候才顯示“沒有找到匹配的城市”字眼,但是這樣會造成一個問題,就是剛開始你不輸入關(guān)鍵詞的時候也會出現(xiàn)這個“沒有找到匹配的城市”字眼,把熱門城市和城市列表給遮住了。這個問題還是可以通過v-show來解決(只不過這次將v-show 標簽加到search-content類上):
<div class="search-content" v-show="keyword" ref="search">
<ul>
<li class="search-item border-bottom" v-for="item of list" :key="item.id">{{ item.name }}</li>
</ul>
<ul>
<li class="search-item border-bottom" v-show="!list.length">沒有找到匹配的城市</li>
</ul>
</div>
這樣就完美地解決了上述問題。前面介紹過html中最好不需要包含計算邏輯(在“沒有找到匹配的城市”標簽上使用了取反運算):
<li class="search-item border-bottom" v-show="!list.length">沒有找到匹配的城市</li>
因此需要將這個取反的邏輯使用計算屬性來代替:
computed: {
hasNoData () {
return !this.list.length
}
},
自然而然就需要修改上面的template中的取反運算代碼為:
<li class="search-item border-bottom" v-show="hasNoData">沒有找到匹配的城市</li>
這樣就完成了搜索框的業(yè)務(wù)邏輯。最后就是將我們的代碼上傳到city-search-logic分支,并且將其與master分支進行合并,相應(yīng)的步驟如下:
于企業(yè)多地點業(yè)務(wù)而言,SEO 策略與業(yè)務(wù)策略的協(xié)調(diào)對于成功至關(guān)重要。
無論企業(yè)是經(jīng)營特許經(jīng)營模式、零售連鎖店,還是以服務(wù)區(qū)業(yè)務(wù)的形式運營多個中心,您的本地 SEO方法都需要量身定制,以滿足您的特定目標。它還需要具有足夠的可擴展性和效率,以便在獲得長期投資回報的同時進行維護。
另一個關(guān)鍵要求是,您的內(nèi)容方法要為用戶和 Google 創(chuàng)造足夠的價值,以使其高于索引質(zhì)量閾值。
這意味著超越本地 SEO 的標準最佳實踐 ,并創(chuàng)建可持續(xù)提高品牌知名度和轉(zhuǎn)化率的本地 SEO 活動。
多地點經(jīng)營的企業(yè)有不同的目標。
雖然多地點管理的基礎(chǔ)相同,但您的方法需要與整體戰(zhàn)略相結(jié)合并與整體業(yè)務(wù)目標保持一致。
例如,在多個城鎮(zhèn)、城市和州經(jīng)營服務(wù)業(yè)務(wù)的多家運營商的戰(zhàn)略特許經(jīng)營業(yè)務(wù)與在多個州擁有數(shù)百家分店的大型倉儲式商店有所不同。
成功指標也各不相同。通常,企業(yè)本地 SEO 活動的 KPI 屬于以下類別之一:
企業(yè)對“成功”的定義將極大地影響您為用戶創(chuàng)建選擇架構(gòu)的方法以及報告成功的方式。
多年來,我們描述和制作多區(qū)域服務(wù)頁面的方法發(fā)生了變化。
十年前,我們會將質(zhì)量低下的版本(只有細微修改且內(nèi)容基本相同)稱為門頁,而谷歌隨著時間的推移逐漸降低了門頁的價值。
近年來,隨著程序化 SEO(pSEO)的日益普及,這種方法已經(jīng)成為大規(guī)模創(chuàng)建這些頁面的流行方法。
對于運營數(shù)百或數(shù)千個門店的企業(yè)來說,程序化或部分程序化內(nèi)容創(chuàng)建可能是一個有吸引力的選擇。
程序化 SEO(簡稱 pSEO)可讓您大規(guī)模生成大量內(nèi)容。這種方法已幫助許多企業(yè)擴大規(guī)模,但如果所創(chuàng)建的頁面無法提供足夠獨特的價值主張,讓 Google 不愿投入資源,那么這種方法也會帶來問題。
如果我們看一下本地服務(wù)頁面的兩個常見網(wǎng)站架構(gòu),我們通常有一個中央服務(wù)頁面,然后是本地服務(wù)頁面,或者有一個充當區(qū)域設(shè)置服務(wù)頁面網(wǎng)關(guān)的中央頁面 - 例如商店定位器。
圖片來自作者,2024 年 7 月
根據(jù)您的業(yè)務(wù)類型,您可能會默認選擇一種結(jié)構(gòu),但兩者都可能帶來挑戰(zhàn)。
使用中央服務(wù)頁面結(jié)構(gòu),您可能會遇到創(chuàng)建獨特價值主張的問題,并確保每個頁面都具有足夠的差異化并高于 Google 索引的質(zhì)量閾值。
商店定位器頁面方法可能會導(dǎo)致 PageRank 分布以及內(nèi)部鏈接到不同位置的方式出現(xiàn)問題。大多數(shù)用戶友好的商店位置應(yīng)用程序不會加載 HTML 鏈接,因此雖然可以直觀地鏈接到所有商店,但 Google 無法抓取這些鏈接。
然而,這兩種方法的共同問題是如何捕獲位置周圍“更廣泛”的搜索。
當本地頁面最適合位置時,它們會發(fā)揮最大的幫助。
從歷史上看,我看到一些公司通過在頁面上“夸大”該地區(qū)的額外信息來做到這一點,比如一兩段關(guān)于當?shù)鼗A(chǔ)設(shè)施、學校和運動隊的段落——如果你想讓人們訪問你的五金店或詢問你的上門安全裝配服務(wù),這些信息都與你無關(guān)。
僅僅更改 URL、H1、標題標簽和整個正文中的位置名稱也是不夠的。
當這種情況發(fā)生時,谷歌實際上會看到近似重復(fù)的頁面,這些頁面在與用戶查詢相關(guān)的價值主張上幾乎沒有區(qū)別。
這種情況的癥狀是,當頁面在 Search Console 中顯示為未編入索引時,Google 要么選擇覆蓋用戶聲明的規(guī)范,要么停留在“已發(fā)現(xiàn)”或“已抓取”的階段,而當前尚未編入索引。
本地服務(wù)和位置頁面之間總會存在一定程度的重復(fù)。Google 對此并不介意。某些內(nèi)容在多個頁面上重復(fù)并不意味著其質(zhì)量低下。
這是我傾向于采用部分程序化方法的地方。
程序化可以滿足 70% (+) 的頁面內(nèi)容;它可以涵蓋您針對特定位置的服務(wù)產(chǎn)品、定價和公司信息。
該頁面的剩余百分比是手動的,但允許您創(chuàng)建與其他頁面的價值主張差異化。
假設(shè)您是一家跨州快遞服務(wù)公司,擁有多條市場路線,您在德克薩斯州的主要配送中心位于奧斯汀、圣安東尼奧和達拉斯,而您想要瞄準尤利斯的潛在客戶。
您為尤利斯提供的服務(wù)與您為普弗拉格維爾、凱爾和利安德的客戶提供的服務(wù)相同 - 因此每個位置頁面的這些部分在所有位置上都是相同的。
但是尤利斯由達拉斯樞紐提供服務(wù),而其他機場則由奧斯汀樞紐提供服務(wù)——這是您要強調(diào)的第一個內(nèi)容差異點。
然后,您可以使用來自企業(yè)內(nèi)部的數(shù)據(jù)和關(guān)鍵字研究,用旅行時間數(shù)據(jù)充實這些頁面。
在尤利斯尋找快遞服務(wù)的客戶可能正在尋找從尤利斯到奧斯汀或從尤利斯到休斯頓的服務(wù)——因此,將此構(gòu)建到本地頁面并提供從目的地到熱門地點的時間估算,可以顯示出本地的專業(yè)性并幫助客戶更好地了解服務(wù)和計劃。
您的業(yè)?務(wù)數(shù)據(jù)還將幫助您識別客戶類型。例如,在尤利斯預(yù)訂的許多工作可能針對的是搬出校園居住的大學生,因此這又是針對可以包含在頁面上的客戶群的更具本地化的定位。
當涉及到內(nèi)部鏈接時,使用偽 HTML 站點地圖可以幫助實現(xiàn)這一點,它不僅可以充當通過頁面的干凈內(nèi)部鏈接,而且還對用戶有益,并允許您創(chuàng)建其他登錄頁面來定位縣或地區(qū)級搜索。
十年前,在一個房產(chǎn)查找頁面上,我所在的團隊構(gòu)建了“縣 > 鎮(zhèn)/市”的頁面結(jié)構(gòu)模式,同時將相關(guān)位置拉入登錄頁面。
作者截圖,2024 年 7 月
從視覺上看,這只是一種更“手動”的方法,讓用戶可以從非特定位置的頁面篩選到他們所在的當?shù)貐^(qū)域。
另一個經(jīng)常被忽視的關(guān)鍵組件是將 Google 商業(yè)資料(GBP) 直接鏈接到網(wǎng)站上的相關(guān)位置頁面。
我遇到過許多跨國公司和國內(nèi)公司,他們鏈接回自己的公司主頁,有時還帶有一個參數(shù)來突出顯示用戶點擊的是哪個 GBP——但這既是糟糕的網(wǎng)絡(luò)架構(gòu),也是糟糕的用戶選擇架構(gòu)。
如果用戶正在尋找 XYZ 中的服務(wù)/商店,他們不希望在點擊網(wǎng)站鏈接時看到主頁或通用信息頁面。
就用戶選擇架構(gòu)而言,從這里,用戶可以導(dǎo)航到不同的商店或頁面,并錯過與他們相關(guān)的關(guān)鍵信息,否則這些信息可能會推動銷售或詢問。
除了 Google 的核心算法和更通用的搜索排名信號外,Google 還發(fā)布了專門針對本地查詢的更新。主要有兩個:
這些更新使企業(yè)更難以欺騙自己在當?shù)厥袌龅拇嬖冢⑶铱赡軣o法提供符合或滿足搜索者需求的價值主張。
據(jù)傳,谷歌似乎優(yōu)先對提供最全面信息的企業(yè)進行排名。
這包括開業(yè)日期、現(xiàn)場餐飲選擇(如果適用)、特殊營業(yè)時間、業(yè)務(wù)類別、服務(wù)列表以及定義服務(wù)區(qū)域和服務(wù)類型。
遵循指南是必須的,但即便如此,你仍可能會違反 Google 的自動檢測檢查。
與一家在亞洲擁有多個辦事處的國際軟件公司合作,在共享辦公室中租用了許多樓層。
我們假設(shè),Google 偶爾會檢測到共享地址并誤認為它們是虛擬辦公室/虛假地址,而Possum 算法更新旨在減少這種情況。
當您與擁有大量實際位置的企業(yè)組織合作時,通過內(nèi)部利益相關(guān)者管理以及了解 GBP 如何適應(yīng)并貢獻于總體目標和生態(tài)系統(tǒng),Google 商家資料管理方法可能會變得更加復(fù)雜。
根據(jù)您的目標,報告成功的方式將因活動而異。
通過 Google API,您可以訪問展示次數(shù)的列表級數(shù)據(jù),以及不同用戶互動的細分(從 GSC 鏡像指標推斷展示次數(shù)和點擊次數(shù))。
非典型的 Google Business Profile 報告儀表板。(作者截圖,2024 年 7 月)
在我看來,任何在多個城鎮(zhèn)、城市、縣或州運營的企業(yè)都需要擁有某種形式的 GBP 監(jiān)控和報告可見性,而不僅僅是在 Google Search Console 和其他分析平臺中跟蹤參數(shù)化 URL(假設(shè)您在 GBP 網(wǎng)站鏈接上使用參數(shù))。
省市區(qū)三級聯(lián)動所需文件:評論回復(fù)區(qū)
文件說明:
整個文件為一個大的對象(非數(shù)組類型)
其中對象的屬性名 100000 中包含所有省份,它也是一個對象格式的;
對象名為100000的每個屬性中的屬性名都為數(shù)字類型(其實是該地區(qū)的行政代碼)。數(shù)字屬性名對應(yīng)的屬性值是該地區(qū)的名稱,同時也可以通過該屬性名訪問到它下級的市列表。
eg:
import districts from './js/districts.js' console.log(districts[100000])
比如當我們想獲取到行政代碼130000河北省下面的市級列表時:
import districts from './js/districts.js' console.log(districts[130000])
然后當我們想獲得行政代碼130100石家莊市下的區(qū)級列表時:
import districts from './js/districts.js' console.log(districts[130100])
沒錯,省市中的每一個行政代碼屬性名都對應(yīng)著它下一級(省行政代碼對應(yīng)市列表,市行政代碼對應(yīng)區(qū)列表)的對象列表。不存在數(shù)組對象嵌套。及其簡單方便。
創(chuàng)建 option 標簽簡便API
new Option('innerText', 'value屬性對應(yīng)的值')
類似于傳統(tǒng)寫法:
let option_1=document.createElement('option')
option_1.text='innerText'
option_1.value='value屬性對應(yīng)的值'
嗯,沒什么區(qū)別,但是第一種簡單很多:
清空 select標簽中的option標簽極簡方法:
selectDOM.options.length=0
.html文件中使用模塊化
將 script 標簽改為 type 屬性改為 module <script type="module">
創(chuàng)建三個 select標簽,分別用來存放 省級列表,市級列表,區(qū)級列表,并定義好變量:
HTML:
<!-- 省級列表 --> <select id="province"></select> <!-- 市級列表 --> <select id="city"></select> <!-- 區(qū)級列表 --> <select id="area"></select>
JS:
// 獲取省市區(qū)selectDOM節(jié)點 let oProvince=document.getElementById('province') let oCity=document.getElementById('city') let oArea=document.getElementById('area')
定義一個特定對應(yīng),用戶將用戶選中的結(jié)果獲取到:
let data={ province: {}, city: {}, area: {} }
1,引入省市區(qū)文件 import districts from './js/districts.js'
直接一個for in 循環(huán) districts[100000] 即可;
然后在循環(huán)中創(chuàng)建option標簽,并插入到省級select節(jié)點中:
let provinceList=districts[100000] for (let province in provinceList) { oProvince.options.add( new Option(provinceList[province], province) ) }
效果:
這樣我們的第一個select標簽就完成了
ps: 市級列表市基于省級之后才開始渲染的,所以應(yīng)該在省級select改變之后觸發(fā)(onchange事件)
1,首先拿到用戶選中的是第幾個option;
通過selectDOM的selectedIndex可拿到對應(yīng)索引值:
然后通過children獲取option子元素列表,之后直接拿對應(yīng)索引即可!
eg: this.children[this.selectedIndex], 因為是onChange事件,this指代selectDOM。
在操作之前,可以先把用戶選中的省份數(shù)據(jù)存放在我們提前定義好的data對象中的province對象中:
data.province.code=this.children[this.selectedIndex].value data.province.value=this.children[this.selectedIndex].text
即此時數(shù)據(jù)應(yīng)為是:
在數(shù)據(jù)存完之后我們就可以著手渲染我們的市級select標簽了。
1,首先不管市級select中有沒有option標簽,我們先給它清除一遍(因為每個省份對應(yīng)的市都不一樣,如果不清除則下面渲染的市級option列表中含有上一個省份的市級option列表)
oCity.options.length=0
2,清除完成之后我們用省級行政代碼(code)去獲取對應(yīng)的市級列表即可:
即districts['省級行政代碼'] 等于對應(yīng)市級列表
districts[data.province.code] // 獲取用戶選中的省份的市級列表
eg:
拿到該省份的對應(yīng)市級列表之后,我們只需要向渲染省級列表一樣渲染市級列表即可:
第三步同第二步基本完全一樣,我們完全可以讓它兩共用一個函數(shù):
在市級列表的onChange事件觸發(fā)之后執(zhí)行,
存儲用戶選中的市的code以及市名。
用獲取到的市級code去換對應(yīng)的區(qū)級列表即可(因為不存在數(shù)組對象嵌套,所以同省級code換市列表一樣);
districts[data.province.code] // 獲取用戶選中的市級的區(qū)級列表
在渲染區(qū)級之前先清空一直區(qū)級select下的option標簽列表
eg:
代碼同上基本一樣,除了需要注意此時我們的存值的對應(yīng)是我們事先定義好的市級對應(yīng)city而不是province即可。
區(qū)級的 onChange 事件觸發(fā),此時我們已經(jīng)不需要再給渲染新的 select 標簽了(因為不是四級聯(lián)動,其實都一樣啦,大不了再復(fù)制一層唄)。所以我們只需要把用戶選中的結(jié)果存放在我們事先定義好的 data 中的 area 區(qū)級對象即可。
這樣,當用戶選擇完畢之后,我們就會得到一個很清晰的對象了。
至此基本完工。
初步渲染完成時應(yīng)該給它下級一個默認值,這樣如果用戶不選了不至于獲取到的數(shù)據(jù)不完整:
1,渲染完省級列表時默認給它一個選中的市,并存值。
使用element.dispatchEvent().。實現(xiàn)onChange事件初始化觸發(fā)
參考資料:https://www.jianshu.com/p/5f9027722204
此時瀏覽器剛刷新數(shù)據(jù)為:
源碼(不含省市區(qū)文件,省市區(qū)文件將開頭):
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style type="text/css"> select { height: 30px; margin-right: 10px; } </style> </head> <body> <!-- 省級列表 --> <select id="province"></select> <!-- 市級列表 --> <select id="city"></select> <!-- 區(qū)級列表 --> <select id="area"></select> <script type="module"> // 引入省市區(qū)文件 import districts from './js/districts.js' // 獲取省市區(qū)selectDOM節(jié)點 let oProvince=document.getElementById('province') let oCity=document.getElementById('city') let oArea=document.getElementById('area') // 存儲用戶選中的值 let data={ province: {}, city: {}, area: {} } // 渲染省級select標簽 let provinceList=districts[100000] for (let province in provinceList) { oProvince.options.add( new Option(provinceList[province], province) ) } // 當用戶選中某個省份時觸發(fā) oProvince.addEventListener('change', function() { // 先清空之前的市級<select>標簽下的option列表 oCity.options.length=0 // 保存省級數(shù)據(jù) data.province.code=this.children[this.selectedIndex].value data.province.value=this.children[this.selectedIndex].text // 渲染市級列表 for(let city in districts[data.province.code]) { oCity.options.add( new Option(districts[data.province.code][city], city) ) } }, false) // 當用戶選中某個市時觸發(fā) oCity.addEventListener('change', function() { oArea.options.length=0 // 保存市級數(shù)據(jù) data.city.code=this.children[this.selectedIndex].value data.city.value=this.children[this.selectedIndex].text // 渲染區(qū)級列表 for(let city in districts[data.city.code]) { oArea.options.add( new Option(districts[data.city.code][city], city) ) } }, false) // 當用戶選中每個區(qū)時觸發(fā) oArea.onchange=function () { // 保存區(qū)級數(shù)據(jù) data.area.code=this.children[this.selectedIndex].value data.area.value=this.children[this.selectedIndex].text } /** * 渲染完成初始化 * @params dom selectDOM */ function initSelect (dom) { let createE=document.createEvent('HTMLEvents') createE.initEvent("change", true, true) dom.dispatchEvent(createE) } initSelect(oProvince) initSelect(oCity) initSelect(oArea) console.log(data) </script> </body> </html>
至此基本完成啦。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。