代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="#" type="image/x-icon" />
<title>free-api-use-by-react</title>
<style>
html,
body,
#app {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
#app {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
padding-top: 10px;
overflow-y: auto;
background-image: url('http://api.botwl.cn/api/bing?type=image');
}
.container {
width: 300px;
height: 400px;
margin: 10px;
padding: 10px;
border-radius: 20px;
text-align: center;
border: 1px solid #dfd4d44d;
box-shadow: 2px 3px 1px 0px #dfd4d44d;
background-color: rgba(255, 255, 255, 0.85);
}
.title {
cursor: pointer;
user-select: none;
}
.pray-sticks .content {
display: flex;
align-items: start;
justify-content: space-evenly;
height: calc(100% - 110px);
cursor: pointer;
}
.pray-sticks p {
writing-mode: vertical-lr;
cursor: auto;
}
.netease-music .preview {
width: 40%;
height: 40%;
border-radius: 50%;
cursor: pointer;
}
@keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.netease-music .preview-rotation {
transform: rotate(360deg);
-webkit-transform: rotate(360deg);
animation: rotation 10s linear infinite;
-moz-animation: rotation 10s linear infinite;
-webkit-animation: rotation 10s linear infinite;
-o-animation: rotation 10s linear infinite;
}
audio:focus,
input,
button,
video,
video:focus {
outline: none;
border: none;
}
button {
height: 28px;
cursor: pointer;
}
.short-video .content {
display: flex;
height: 80%;
}
.short-video .content .left {
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 10px;
font-size: 30px;
}
.short-video .content .left span {
cursor: pointer;
}
.short-video .content .right {
flex: 1;
}
.short-video .video {
width: 70%;
height: 100%;
object-fit: fill;
border-radius: 1.5%;
cursor: pointer;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<!-- <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script> -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
// https://bird.ioliu.cn/v2/ 可以作为 HTTP 代理接口
const proxyInterface = 'https://bird.ioliu.cn/v2/'
const ele = React.createElement
const useState = React.useState
const useEffect = React.useEffect
const useRef = React.useRef
/**
* @name 看图猜成语
* @description 1. 点击图片切换成语; 2. 鼠标移入答案双箭头中间位置显示成语
* @tip react 原始的写法 + axios
*/
class GuessIdiom extends React.Component {
constructor(props) {
super(props)
this.state = {
imgUrl: '',
idiom: '',
}
}
getIdiom = () => {
axios.get(`${proxyInterface}?url=http://api.botwl.cn/api/ktccy`).then(({ data }) => {
this.setState({ imgUrl: data.img })
this.setState({ idiom: data.msg })
})
}
componentDidMount() {
this.getIdiom()
}
render() {
return ele('section', { className: 'container' }, [
ele('h2', { key: 'title' }, '看图猜成语'),
ele('img', {
key: 'img',
src: this.state.imgUrl,
alt: 'img',
title: '点击换图',
style: { cursor: 'pointer', width: '70%', objectFit: 'contain' },
onClick: this.getIdiom,
}),
ele('h4', { key: 'idiom-text', className: 'idiom-text', style: { fontSize: '24px' } }, [
`答案: → `,
ele(
'span',
{
key: 'idiom',
style: { opacity: 0, cursor: 'pointer' },
onMouseEnter: (e) => (e.target.style.opacity = 1),
onMouseLeave: (e) => (e.target.style.opacity = 0),
},
`${this.state.idiom}`
),
` ←`,
]),
])
}
}
/**
* @name 求签
* @description 1. 双击卡片标题重新求签
* @tip class + jsx + axios
*/
class PraySticks extends React.Component {
state = {
// 签诗
sticksPoem: '',
// 解签
sticksResolve: '',
}
handlePraySticks = async () => {
let { data } = await axios.get(`${proxyInterface}?url=http://api.botwl.cn/api/qiuqian`)
// 签诗
const sticksPoem = data.split('[\\n]')[0]
// 解签
const sticksResolve = data.split('[\\n]')[1]
this.setState({ sticksPoem, sticksResolve })
}
componentDidMount() {
this.handlePraySticks()
}
render() {
const { sticksPoem, sticksResolve } = this.state
return (
<React.Fragment>
<section className='container pray-sticks'>
<h2 className='title' title='双击重抽' onDoubleClick={this.handlePraySticks}>
求签
</h2>
<div className='content'>
<p dangerouslySetInnerHTML={{ __html: sticksPoem }} />
<p dangerouslySetInnerHTML={{ __html: sticksResolve }} />
</div>
</section>
</React.Fragment>
)
}
}
/**
* @name 网易云音乐
* @description 1. 搜索音乐; 2. 封面点击播放/暂停音乐
* @tip 函数组件 + hooks + jsx + fetch
*/
const NeteaseMusic = () => {
const [songKeyword, setSongKeyword] = useState('Numb - Linkin Park')
const [songInfo, setSongInfo] = useState({})
const [playing, setPlaying] = useState(false)
const audioPlayerDOM = document.querySelector('#audio-player')
// 搜索歌曲
const searchSong = () => {
fetch(`${proxyInterface}?url=http://api.botwl.cn/api/wyy?msg=${songKeyword}&type=json&n=1`).then(
async (res) => {
const originData = await res.text()
const data = JSON.parse(originData.replace('json:', '')).meta.music
setSongInfo(data)
}
)
}
// 提交
const handleSubmit = (e) => {
e.preventDefault()
searchSong()
}
// 播放/暂停
const handlePlayAndPause = () => {
const playingStatus = !playing
setPlaying(playingStatus)
playingStatus ? audioPlayerDOM.play() : audioPlayerDOM.pause()
}
useEffect(() => {
document.querySelector('#audio-player').volume = 0.5
searchSong()
}, [])
return (
<section className='container netease-music'>
<h2 className='title'>网易云音乐</h2>
<form onSubmit={handleSubmit}>
<input
type='text'
placeholder='请输入歌名'
value={songKeyword}
onChange={(e) => setSongKeyword(e.target.value)}
style={{ width: '70%', height: 26, borderRadius: 4 }}
/>
  <button>搜索</button>
<div className='content'>
<p>
<img
onClick={handlePlayAndPause}
src={songInfo.preview}
className={`preview ${playing ? 'preview-rotation' : ''}`}
/>
</p>
<p>歌名: {songInfo.title}</p>
<p>歌手: {songInfo.desc}</p>
<p>
<audio
id='audio-player'
autoPlay
controls
onPlay={() => setPlaying(true)}
onPause={() => setPlaying(false)}
onEnded={() => setPlaying(false)}
src={songInfo.musicUrl}
style={{ width: '90%', height: 30 }}
>
您的浏览器不支持 audio 元素。
</audio>
</p>
</div>
</form>
</section>
)
}
/**
* @name 短视频
* @description 1. 切换视频
* @tip 函数组件 + hooks + jsx + fetch
*/
const ShortVideo = () => {
const [timestamp, setTimestamp] = useState(Date.now())
// 是否静音
const [muted, setMuted] = useState(true)
// 是否全屏
const [isFullScreen, setIsFullScreen] = useState(false)
// 是否自动切换
const [autoSwitch, setAutoSwitch] = useState(false)
const videoRef = useRef()
// 全屏
const handleFullScreen = () => {
const documentEle = document.documentElement
if (documentEle.requestFullscreen) {
videoRef.current.requestFullscreen()
} else if (documentEle.mozRequestFullScreen) {
videoRef.current.mozRequestFullScreen()
} else if (ele.webkitRequestFullScreen) {
videoRef.current.webkitRequestFullScreen()
}
}
// 全屏状态改变
document.addEventListener('fullscreenchange', (e) => {
setIsFullScreen(!isFullScreen)
})
return (
<section className='container short-video'>
<h2 className='title'>短视频</h2>
<div className='content'>
<div className='left'>
<span style={{ color: muted ? '#aaa' : '#000' }} title='是否静音' onClick={() => setMuted(!muted)}>
♪
</span>
<span onClick={() => setTimestamp(Date.now())} title='换一个'>
↻
</span>
<span
style={{ color: autoSwitch ? '#000' : '#aaa' }}
title='自动切换'
onClick={() => setAutoSwitch(!autoSwitch)}
>
✲
</span>
<span style={{ color: isFullScreen ? '#000' : '#aaa' }} title='全屏控制' onClick={handleFullScreen}>
❏
</span>
</div>
<div className='right'>
<video
className={isFullScreen ? '' : 'video'}
ref={videoRef}
autoPlay
loop={!autoSwitch}
muted={muted}
onClick={(e) => (e.target.paused ? e.target.play() : e.target.pause())}
onVolumeChange={(e) => setMuted(e.target.muted)}
onEnded={(e) => setTimestamp(Date.now())}
onDoubleClick={handleFullScreen}
// src='https://www.runoob.com/try/demo_source/mov_bbb.mp4'
// src={`https://tucdn.wpon.cn/api-girl/index.php?wpon=302&t=${timestamp}`}
src={`https://v.api.aa1.cn/api/api-dy-girl/index.php?aa1=ajdu987hrjfw&t=${timestamp}`}
></video>
</div>
</div>
</section>
)
}
/**
* @name 虎牙主播信息
* @description 1. 主播信息搜索
* @tip 函数组件 + hooks + jsx + fetch
*/
const HuYa = () => {
const [anchorKeyword, setAnchorKeyword] = useState('呆妹儿')
const [anchorInfo, setAnchorInfo] = useState({})
// 搜索主播信息
const searchAnchorInfo = () => {
// 空值判断
if (!anchorKeyword.trim()) return false
fetch(`${proxyInterface}?url=http://api.botwl.cn/api/huya?msg=${anchorKeyword}&n=1`).then(async (res) => {
const originData = await res.text()
// 切割返回的数据
const splitData = originData.split('\n')
// 主播信息(临时值)
const anchorInfoTemp = {}
// 长度为1,表示查不到主播信息
if (splitData.length === 1) {
const key = splitData[0]
const value = ''
anchorInfoTemp[key] = value
}
// ※ 由于列表搜索接口经常搜不到,所以先注释 ※
// 第一项不包含 '±img=',则搜索结果为主播列表
// else if (!splitData[0].includes('±img=')) {
// splitData.forEach((item) => {
// // unicode 编码转换中文
// const chineseItem = eval("'" + item.replace(':', ': ') + "'")
// const value = chineseItem.split(': ')[1] && eval("'" + chineseItem.split(': ')[1] + "'")
// const key = chineseItem.split(': ')[0] + (value ? ':' : '')
// anchorInfoTemp[key] = value
// })
// }
else {
const imgUrl = splitData[0].replace('±img=', '')
anchorInfoTemp.imgUrl = imgUrl
splitData.splice(1).forEach((item) => {
const chineseItem = item.split(':')
const key = chineseItem[0] + ':'
// unicode 编码转换中文
const value = chineseItem[1] && eval("'" + chineseItem[1] + "'")
anchorInfoTemp[key] = value
})
}
setAnchorInfo({ ...anchorInfoTemp })
})
}
useEffect(() => {
searchAnchorInfo()
}, [])
return (
<section className='container hu-ya'>
<h2 className='title'>虎牙主播信息</h2>
<form
style={{ paddingBottom: 20 }}
onSubmit={(e) => {
e.preventDefault()
searchAnchorInfo()
}}
>
<input
type='text'
placeholder='请输入主播信息'
value={anchorKeyword}
onChange={(e) => setAnchorKeyword(e.target.value)}
style={{ width: '70%', height: 26, borderRadius: 4 }}
/>
  <button>搜索</button>
</form>
{Object.keys(anchorInfo).map((key) =>
key === 'imgUrl' ? (
<img
key={key}
src={anchorInfo[key]}
alt='anchor'
style={{ width: 80, height: 80, borderRadius: '5%', objectFit: 'fill' }}
/>
) : (
<div key={key}>
{key}
{anchorInfo[key] && anchorInfo[key].includes('http') ? (
<a href={anchorInfo[key]} target='_blank'>
{anchorInfo[key]}
</a>
) : (
anchorInfo[key]
)}
</div>
)
)}
</section>
)
}
const root = ReactDOM.createRoot(document.getElementById('app'))
root.render([
ele(GuessIdiom, { key: 'GuessIdiom' }),
ele(PraySticks, { key: 'PraySticks' }),
ele(NeteaseMusic, { key: 'NeteaseMusic' }),
ele(ShortVideo, { key: 'ShortVideo' }),
ele(HuYa, { key: 'HuYa' }),
])
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。