react頁面引導元件, 支援語音播報

Jike發表於2019-04-07

頁面引導在使用者第一次訪問網站能過提供很好的提示, 下面介紹基於react寫的一個頁面引導的元件. 演示地址

效果圖

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.

react頁面引導元件, 支援語音播報

再新增上resize事件監聽, 在頁面縮放時,也能重新佈局

window.addEventListener('resize', this.onRezieWindow.bind(this), false)
複製程式碼

內容區

首先確定要顯示內容區的位置, 通過目標domoffsertLeftoffsetTopheightwidth, 獲取內容區的位置

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
  }
})
複製程式碼

react頁面引導元件, 支援語音播報

內容區也在遮罩層之上.啟用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)
複製程式碼

語音功能

語音功能可以用HTML5audio標籤

<audio ref='audio' src={this.state.audioUrl} type="audio/mpeg"></audio>}
複製程式碼

再結合百度的ttsAPI

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)的結果

通過audioapi控制停止、播放

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-guideapi

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'));
複製程式碼

相關文章