頁面引導在使用者第一次訪問網站能過提供很好的提示, 下面介紹基於react
寫的一個頁面引導的元件.
演示地址
效果圖
Guide元件的實現
可以把<Guide/>
設計成一個容器元件, 因為我們不知道要引導的內容是什麼, 通過容器元件的this.props.children
渲染內容
class Guide extends Component {
render () {
return (
<div className="guide-container" ref='guide'>
{this.props.children}
</div>
)
}
}
複製程式碼
如何獲取哪些是要引導的dom
? 可以通過dom的自定義屬性, 再通過querySelectorAll
獲取
// example
<Guide >
<header data-step="1" data-tip='Welcome to use react-guide'>React Guide</header>
</Guide>
// 獲取要引導的dom
this.refs.guide.querySelectorAll('[data-step]')
複製程式碼
<Guide/>
元件還需要有: 遮罩層、提示框、內容區、語音功能, 4個部分.
遮罩層
遮罩層通過fixed
佈局,加個透明度就好了, 通過外面傳來的visible
控制顯示
class Guide extends Component {
render () {
return (
<div className="guide-container" ref='guide'>
{this.props.children}
{this.props.visible&&<div className="guide-shadow" ref='shadow' onClick={this.onClickShadow.bind(this)} key='guide-shadow'></div>}
</div>
)
}
}
複製程式碼
提示框
提示框應該再遮罩層之上, 它的z-index
大於遮罩層的.提示框還要考慮頁面空餘空間,確定擺放位置,如下圖的4個位置, 1, 4 位置放不下, 所以可以放2, 3.
再新增上resize
事件監聽, 在頁面縮放時,也能重新佈局
window.addEventListener('resize', this.onRezieWindow.bind(this), false)
複製程式碼
內容區
首先確定要顯示內容區的位置, 通過目標dom
的offsertLeft
、offsetTop
、height
、width
, 獲取內容區的位置
const nodeList = getListFromLike(this.refs.guide.querySelectorAll('[data-step]')) // 獲取所有要引導dom
nodeList.sort((a, b) => {
return Number(a.getAttribute('data-step'))- Number(b.getAttribute('data-step'))
}) // 按照step的大小進行排序
let dots = nodeList.map(node => {
let height = node.clientHeight || node.offsetHeight
let width = node.clientWidth || node.offsetWidth
return {
left: node.offsetLeft,
top: node.offsetTop,
height,
width,
tip: node.getAttribute('data-tip'),
step: node.getAttribute('data-step'),
fRight: node.offsetLeft + width,
fBottom: node.offsetTop + height
}
})
複製程式碼
內容區也在遮罩層之上.啟用content
時只要給原dom
新增上z-index
node.style.setProperty('position', 'relative');
node.style.setProperty('z-index', '999996', 'important');
複製程式碼
當頁面存在滾動條時, 還要頁面的滾動到要引導區域, 通過scrollTo(x, y)
實現
window.scrollTo(dLeft - 100, dTop - 100)
複製程式碼
語音功能
語音功能可以用HTML5
的audio
標籤
<audio ref='audio' src={this.state.audioUrl} type="audio/mpeg"></audio>}
複製程式碼
再結合百度的tts
的API
function text2Voice(tip, lan){
let obj = {
lan,
ie: 'UTF-8',
spd: '4',
per: 4,
text: tip // tip就是dom上data-tip的屬性值
}
return 'http://tts.baidu.com/text2audio' + axiosObj(obj)
}
複製程式碼
把audio
標籤的src
指向text2Voice(tip, lan)
的結果
通過audio
的api
控制停止、播放
this.refs.audio.autoplay = true // 自動播放
this.refs.audio.pause() // 暫停
this.refs.audio.addEventListener('timeupdate', () => {
... // 監聽什麼時候結束
}, false)
複製程式碼
說明
原始碼及api
➡️github, 歡迎star
,感謝.
安裝
可以通過npm
安裝
$ npm install react-guide
複製程式碼
API
下面是react-guide
的api
Property | Description | Type | Default |
---|---|---|---|
visible | Whether the guide is visible or not | boolean | false |
audio | Whether a voice reads of tip of the guide or not | boolean | true |
lan | The voice of language, 'en' or 'zh' | string | en |
bullet | Whether bullets (.) button is visible on middle of the guide or not | boolean | false |
num | Whether num icon is visible on top left of the guide or not | boolean | false |
onCancel | Specify a function that will be called when a user clicks shadow, skip button on bottom left | function(e) | - |
onOk | Specify a function that will be called when all steps have done and click the done button | function(e) | - |
data-step | Number of steps for guides, only use in dom | string | - |
data-tip | Every step you want to show tip, only use in dom | string | - |
例子
一個例子
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Guide from 'react-guide'
class App extends Component {
constructor () {
super()
this.state = {
visible: false
}
}
handleStart() {
this.setState({
visible: true
})
}
handleCancel() {
this.setState({
visible: false
})
}
render() {
return (
<div>
<Guide
visible={this.state.visible}
onCancel={this.handleCancel.bind(this)} >
<h1 data-step="1" data-tip='Hello World'>Step1</h1>
<div data-step="3" data-tip='Welcome to use react-guide'>Step3</div>
<h4 data-step="2" data-tip='react-guide is very easy' >Step2</h4>
<div><span data-step="4" data-tip='Let start'>Step4</span></div>
</Guide>
<button onClick={this.handleStart.bind(this)}>start</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
複製程式碼