使用React和Ruffle播放Flash
用途
当我们想在React等SPA中使用遗产Flash文件(*.swf)时!
显然,不能依赖于Flash Player。
React + Ruffle + *.swf 或者前端Web框架 + Ruffle + *.swf
直到公开为止
自从Adobe完全终止支持Flash Player后已经很久了。
那是在2020年12月31日发生的事情…。
播放遗产 Flash 文件(*.swf)的方法仍然有需求。
可能需要视频内的可点击部分,
不能简单地将视频转换为MP4。
但是,从头开始使用HTML5+CSS3动画制作也很麻烦。
因此,我尝试验证了Ruffle和swf2js。
如果是静态页面,只需查看Ruffle的官方文档即可轻松实现。
但是对于动态页面或SPA,情况就不那么简单了。
-
- URL が切り替わると再生されない!
-
- Rust から自分でコンパイルすればいいらしい?
- wasm-loader が要るらしいけど、webpack なの? create-react-app なの?
这种感觉非常混乱。
我正在寻找再生的方法,并找到了一个相当简单的解决方案,现在向你介绍。
解决模式,办法,措施
当SPA内的内容被绘制时,会动态地触发自定义事件。
在该自定义事件中,开始播放Flash。
关键词如下:
-
- componentDidMount
-
- dispatchEvent
-
- addEventListener
- CustomEvent
以下的例子使用了 React + TypeScript。 但我认为在 React + JavaScript 或其他前端 Web 框架的情况下,只需做出少量修改即可。
只有一个选项可以用中文本地语言改写:
※ 在ruffle.js中加载*.wasm文件。由于wasm文件的尺寸较大,这种方法不适合希望进行优化的人。这种情况下,从Rust编译可能更好。
这个方法是根据Ruffle官方文档中的描述,是建立在Website Self Hosted的基础上的方法。不需要使用Rust开发环境。
组成
┣━public
┃ ┣━ flash
┃ ┃ ┗━ flash
┃ ┃ ┗━ legacy.swf
┃ ┗━ ruffle
┃ ┗━ ruffle-nightly-2021_05_17-web-selfhosted
┃ ┣━ ???.wasm
┃ ┣━ ...
┃ ┗━ ruffle.js
┗━src
┣━ components
┃ ┣━ fixed_mainnav.tsx
┃ ┣━ header.tsx
┃ ┣━ main.tsx
┃ ┗━ maincontent.tsx
┣━ index.html
┗━ index.tsx
当 JSX 在 maincontent.tsx 中被加载时,会每次播放 legacy.swf。
代码 (Mandarin: “daima”)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
<script src="%PUBLIC_URL%/ruffle/ruffle-nightly-2021_05_17-web-selfhosted/ruffle.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
var config = {
// Options affecting the whole page
"publicPath": "Failed to load the video!",
"polyfills": true,
// Options affecting files only
"autoplay": "true",
"unmuteOverlay": "hidden",
"backgroundColor": null,
"letterbox": "fullscreen",
"warnOnUnsupportedContent": true,
"contextMenu": false,
"upgradeToHttps": window.location.protocol === "https:",
"logLevel": "error",
};
function loadflash(elementId,flashUrl) {
const ruffle = window.RufflePlayer.newest();
const player = ruffle.createPlayer();
const container = document.getElementById(elementId);
container.appendChild(player);
player.config = config;
player.load(flashUrl);
}
function loadflash001() {
loadflash('flash001','%PUBLIC_URL%/flash/legacy.swf');
}
window.addEventListener("playflash", loadflash001);
window.addEventListener("load", loadflash001);
</script>
</html>
在标签内,我们通过以下方式加载了ruffle.js。
<script src="%PUBLIC_URL%/ruffle/ruffle-nightly-2021_05_17-web-selfhosted/ruffle.js"></script>
loadflash是一个播放Flash的函数。
最終目標是在load事件和playflash事件中播放Flash。为什么需要注册在load事件上呢?因为无法通过直接输入URL来触发playflash事件。如果有人能详细验证这方面内容并留下评论,我会很开心。
我尝试直接为loadflash添加了addEventListener,但是发现在load事件发生时也会同时触发playflash事件。因此,我使用loadflash001函数,故意进行两层组合。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.sass';
import reportWebVitals from './reportWebVitals';
import MainApp from "./components/main";
import HeaderApp from "./components/header";
import FooterApp from "./components/footer";
import { createBrowserHistory } from "history"
import { Router } from 'react-router';
const history = createBrowserHistory({ basename: '/new_web' });
ReactDOM.render(
<React.StrictMode>
<Router history = {history}>
<HeaderApp></HeaderApp>
<MainApp></MainApp>
<FooterApp></FooterApp>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals(console.log);
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import OutlineApp from './outline';
import MainContentApp from './maincontent';
class MainApp extends React.Component {
render() {
return (
<main id="wrap_main">
<div id="sidearea"></div>
<div id="wrap_contents">
<Switch>
<Route exact path="/" component={MainContentApp} />
<Route exact path="/outline/" component={OutlineApp} />
<Route render={() => <p>NotFound</p>} />
</Switch>
</div>
<div id="main-right-spacer"></div>
</main >
);
}
}
export default MainApp;
在上述的main.tsx文件中,
<Route exact path="/" component={MainContentApp} />
<Route exact path="/outline/" component={OutlineApp} />
有一部分是这样的。在这里,当URL转移到/时,将加载MainContentApp。
那里有一个想要播放Flash的标签id=’flash001’。
然而,当URL转到/outline/时,将加载OutlineApp而不是MainContentApp。
因此,标签id=’flash001’会消失一次。
当URL再次转换为/时,MainContentApp将再次加载。
tag id=’flash001’将再次出现。
在这种情况下,只使用 window.addEventListener(“load”, func) 是无法播放 Flash 的。
这是因为 load 事件只会在初次加载 DOM 时才会发生。
import React from 'react';
let FlashEvent = new CustomEvent('playflash', { bubbles: true });
class MainContentApp extends React.Component {
componentDidMount() {
window.dispatchEvent(FlashEvent);
}
render() {
return (
<React.StrictMode>
<div id="flash001"></div>
</React.StrictMode>
);
}
}
export default MainContentApp;
在maincontent.tsx中,存在着
。在这里将加载Flash。
此外,在maincontent.tsx中的第2行中,我们声明了一个名为playflash的事件,如下所示。
let FlashEvent = new CustomEvent('playflash', { bubbles: true });
当MainContentApp组件被挂载后,
componentDidMount() {
window.dispatchEvent(FlashEvent);
}
通过这样做,会触发FlashEvent。
这将激活index.html中准备好的playflash事件监听器。
import React from 'react';
import { NavLink } from 'react-router-dom';
import FixedMainNavApp from "./fixed_mainnav";
class HeaderApp extends React.Component {
render() {
return (
<React.StrictMode>
<header id="wrap_header">
<div id="wrap_logo">
<a href="/">
<img id="mainlogo" alt="株式会社logo" />
</a>
</div>
<nav id="wrap_gmenu">
<ul>
<FixedMainNavApp />
</ul>
</nav>
</header>
</React.StrictMode>
);
}
}
export default HeaderApp;
在上述的header.tsx文件中,通过FixedMainNavApp组件加载导航链接。
import React from 'react';
import { Link } from 'react-router-dom';
class FixedMainNavApp extends React.Component {
render() {
return (
<React.StrictMode>
<li><Link to="/">ホーム</Link></li>
<li><Link to="/outline/">会社概要</Link></li>
<li><Link to="/digital/">デジタル事業</Link></li>
<li><Link to="/recruit/">リクルート</Link></li>
<li><Link to="/sitemap">サイトマップ</Link></li>
</React.StrictMode>
);
}
}
export default FixedMainNavApp;
当用户在fixed_mainnav.tsx中点击Link标签时,将进行URL跳转。
整理/总结
抛开负面遗产,才能获得幸福。 加油!