页面引导在用户第一次访问网站能过提供很好的提示, 下面介绍基于react
写的一个页面引导的组件. 演示地址
效果图
Guide组件的实现
可以把<Guide/>
设计成一个容器组件, 因为我们不知道要引导的内容是什么, 通过容器组件的this.props.children
渲染内容
class Guide extends Component {
render () {
return (
<div className="guide-container" ref={e => this.guide = e}>
{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.guide.querySelectorAll('[data-step]')
复制代码
<Guide/>
组件还需要有: 遮罩层、提示框、内容区、语音功能, 4个部分.
遮罩层
遮罩层通过fixed
布局,加个透明度就好了, 通过外面传来的visible
控制显示
class Guide extends Component {
render () {
return (
<div className="guide-container" ref={e => this.guide = e}>
{this.props.children}
{this.props.visible&&<div className="guide-shadow" ref={e => this.shadow = e}s.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.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={e => this.audio = e} 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.audio.autoplay = true // 自动播放
this.audio.pause() // 暂停
this.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'));
复制代码