Commit c6289fe6 authored by 余成's avatar 余成

烽火台创建项目

parent 4381773e
import MD from 'spark-utils/out/md/index.js';
let appId = CFG.appID;
const dcm = '202.' + CFG.projectId + '.0.0';
const domain = '//embedlog.duiba.com.cn';
let MDList = [
{
ele: `.test-md1`,
data: {
dpm: `${appId}.110.5.1`,
dcm,
domain,
appId
},
once: false
}
];
export default () =>
MD({
show: MDList, // 曝光
click: MDList // 点击
});
思维导图地址 # spark-template
https://alidocs.dingtalk.com/i/team/3YxXANaQeaQ3LmNy/docs/3YxXAR7oJbBWLmNy?iframeQuery=mode%3D2
\ No newline at end of file 烽火台app3.0中的静态模板配置
\ No newline at end of file
const { assets } = require("spark-assets");
const args = process.argv.splice(2);
let argsObj = {
imgmin: false,
imgup: false
}
if (args.length == 1) {
argsObj.imgmin = 'imgmin' == args[0];
argsObj.imgup = 'imgup' == args[0];
} else if (args.length == 2) {
argsObj.imgmin = 'imgmin' == args[0];
argsObj.imgup = 'imgup' == args[1];
}
assets(argsObj)
\ No newline at end of file
exports.SPARK_CONFIG_DIR_KEY = ['OUTPUT_DIR', 'SOURCE_DIR', 'TEMP_DIR', 'ENTRY', 'TEMPLATE']
exports.SPARK_CONFIG = 'sparkrc.js'
//对应项目在线素材存储的cdn配置,用于迭代开发从线上拉取素材到本地
exports.SPARK_CDN_RES_CFG='sparkrescfg.json'
\ No newline at end of file
const loaderUtils = require('loader-utils');
module.exports = function (source) {
const options = loaderUtils.getOptions(this);
let result = source;
if (options.arr) {
options.arr.map(op => {
result = result.replace(op.replaceFrom, op.replaceTo);
})
} else {
result = source.replace(options.replaceFrom, options.replaceTo);
}
return result
};
const babel = require('@babel/core');
const HtmlWebpackPlugin = require("html-webpack-plugin");
class HtmlJsToES5Plugin {
process(htmlPluginData) {
return new Promise(function (resolve) {
const scriptRegExp = /<script>[\s\S]*?<\/script>/gis;
htmlPluginData.html = htmlPluginData.html.replace(scriptRegExp, function (match) {
const code = match.replace("<script>", "").replace("</script>", "");
const es5Code = babel.transform(code, { 'presets': ['@babel/preset-env'] }).code;
return `<script>${es5Code}</script>`;
});
resolve();
});
};
apply(compiler){
compiler.hooks.compilation.tap('HtmlJsToES5Plugin', (compilation) => {
HtmlWebpackPlugin.getHooks(compilation).afterTemplateExecution.tapAsync(
"HtmlJsToES5Plugin",
async (html, cb) => {
await this.process(html);
cb(null, html);
}
);
});
}
}
// exports.default = HtmlJsToES5Plugin;
module.exports = HtmlJsToES5Plugin;
// 端口是否被占用
exports.getProcessIdOnPort=function(port) {
try {
const execOptions = {
encoding: 'utf8',
stdio: [
'pipe',
'pipe',
'ignore',
],
};
return execSync('lsof -i:' + port + ' -P -t -sTCP:LISTEN', execOptions)
.split('\n')[0]
.trim();
} catch (e) {
return null;
}
}
const childProcessSync=async function(cmd, params, cwd, printLog = true) {
return new Promise((resolve, reject) => {
let proc = childProcess(cmd, params, cwd, printLog);
proc.on('close', (code) => {
if (code === 0) {
resolve(proc['logContent']);
} else {
reject(code);
}
});
});
}
const getGitBranch=async function(cwd) {
try {
const result = await childProcessSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], cwd, false);
if (!result.startsWith('fatal:')) {
return result.trim();
}
} catch (e) {
return undefined;
}
}
const getProjectNameByPackage=function() {
return require(`${process.cwd()}/package.json`).name
}
/**
* 理论上每个项目独一无二的文件夹名字-默认取分支名
* 如果当前未创建分支,取包名+日期
* (实际很多情况是直接clone老项目,包名相同,以防资源被替换,所以用日期加一下)
*/
exports.getCdnFolderName=async function() {
const branch = await getGitBranch(process.cwd());
const date = Date.now();
if (branch) {
return branch + "/" + date;
}
let foldername = getProjectNameByPackage() + "/" + date;
return foldername;
}
\ No newline at end of file
const path = require('path');
const fs = require("fs");
const { SPARK_CONFIG_DIR_KEY, SPARK_CONFIG } = require('./scripts/constant');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
module.exports = function (isProd) {
const appPath = process.cwd();
const sparkConfig = require(path.join(appPath, SPARK_CONFIG));
const isEslint = fs.existsSync(`${appPath}/.eslintrc.js`);
const cssReg = /\.(css|less)$/;
// 处理相对路径
SPARK_CONFIG_DIR_KEY.map((key) => {
sparkConfig[key] = path.resolve(appPath, sparkConfig[key]);
});
const stylePlugins = [
require("autoprefixer")({
overrideBrowserslist: ["> 1%", "last 2 versions", "not ie <= 8"],
})
];
if (sparkConfig.PX2REM) {
stylePlugins.push(
require("postcss-px2rem-exclude")({
remUnit: 100, // 注意算法,这是750设计稿,html的font-size按照750比例
exclude: /node_modules/i,
})
);
}
const styleLoader = (cssOptions = {}) => {
return [
{
loader: "style-loader",
},
isProd && {
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
{
loader: "css-loader",
options: {
...cssOptions,
importLoaders: 2, // 如果遇到css里面的 @import 执行后面两个loader。 不然如果import了less,css-loader是解析不了
},
},
{
loader: "postcss-loader",
options: {
sourceMap: isProd,
plugins: stylePlugins,
},
},
{
loader: require.resolve("less-loader"),
options: {
sourceMap: isProd,
lessOptions: {
modifyVars: {
"@RES_PATH": `"${isProd ? sparkConfig.RES_PATH_PROD + '/' : sparkConfig.RES_PATH}"`,
},
}
},
},
].filter(Boolean);
};
return {
entry: sparkConfig.ENTRY,
mode: isProd ? 'production' : 'development',
devtool: isProd ? "source-map" : "cheap-module-source-map",
output: {
path: path.resolve(__dirname, sparkConfig.OUTPUT_DIR),
filename: "js/[name].js",
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
"@src": path.resolve(__dirname, sparkConfig.SOURCE_DIR),
},
},
module: {
rules: [
// 提前进行eslint, 默认从下往上,通过enforce pre提前
isEslint && {
test: /\.js|jsx/,
enforce: "pre",
loader: "eslint-loader",
options: {
cache: true,
formatter: require("eslint-friendly-formatter"),
fix: true,
failOnError: true,
configFile: `${appPath}/.eslintrc.js`,
},
include: sparkConfig.SOURCE_DIR,
},
{
test: cssReg,
use: styleLoader(),
include: sparkConfig.SOURCE_DIR,
},
{
test: /\.(js|jsx)$/,
loader: require.resolve("babel-loader"),
exclude: [path.resolve("node_modules")],
options: {
presets: [
require("@babel/preset-env").default,
require("@babel/preset-react").default
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": false }],
require("@babel/plugin-transform-runtime").default,
],
sourceType: 'unambiguous'
},
},
{
test: [/\.(jpg|jpeg|png|svg|bmp)$/, /\.(eot|woff2?|ttf|svg)$/],
loader: require.resolve("url-loader"),
options: {
name: "[path][name].[ext]", // name默认是加上hash值。这里做了更改,不让加
outputPath: "images",
limit: 10240, // url-loader处理图片默认是转成base64, 这里配置如果小于10kb转base64,否则使用file-loader打包到images文件夹下
},
},
].filter(Boolean),
},
plugins: [
isProd &&
new MiniCssExtractPlugin({
filename: "styles/[name].[hash].css",
}),
new HtmlWebpackPlugin({
template: sparkConfig.TEMPLATE,
minify: !sparkConfig.UNMINIFY_INDEX && isProd,
}),
new CleanWebpackPlugin({
// cleanOnceBeforeBuildPatterns:['**/*', 'dist'] // 这里不用写 是默认的。 路径会根据output 输出的路径去清除
}),
new ProgressBarPlugin(),
].filter(Boolean),
optimization: {
minimize: isProd,
minimizer: [
// 替换的js压缩 因为uglifyjs不支持es6语法,
new TerserPlugin({
cache: true,
sourceMap: isProd,
extractComments: false, // 提取注释
parallel: true, // 多线程
terserOptions: {
compress: {
pure_funcs: ["console.log"],
},
},
}),
// 压缩css
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorPluginOptions: {
preset: ["default", { discardComments: { removeAll: true } }],
},
canPrint: true,
}),
],
// 修改文件的ids的形成方式,避免单文件修改,会导致其他文件的hash值变化,影响缓存
moduleIds: "hashed",
splitChunks: {
chunks: "all",
minSize: 30000, //小于这个限制的会打包进Main.js
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10, // 优先级权重,层级 相当于z-index。 谁值越大权会按照谁的规则打包
name: "vendors",
},
},
},
// chunks 映射关系的 list单独从 app.js里提取出来
runtimeChunk: {
name: (entrypoint) => `runtime-${entrypoint.name}`,
},
},
};
}
\ No newline at end of file
const { SPARK_CONFIG } = require("./scripts/constant");
const Webpack = require("webpack");
const webpackBaseConfig = require("./webpack.common.config");
const WebpackMerge = require("webpack-merge");
const WebpackDevServer = require("webpack-dev-server");
const opn = require("opn");
const apiMocker = require('mocker-api');
const path = require('path');
const { getProcessIdOnPort } = require("./scripts/utils");
const sparkConfig = require(path.resolve(SPARK_CONFIG));
const webpackDevConfig = function () {
return {
devServer: {
useLocalIp: true,
open: false,
hot: true,
host: "0.0.0.0",
// hotOnly: true
before(app) {
if (sparkConfig.API_MOCK) {
apiMocker(app, path.resolve('./mock/index.js'), {
changeHost: true,
})
}
}
},
plugins: [
// new Webpack.WatchIgnorePlugin([/[\\/]mock[\\/]/]),
new Webpack.HotModuleReplacementPlugin()
]
};
};
const buildDev = async function (config) {
let { port } = config;
return new Promise((resolve, reject) => {
const config = WebpackMerge(webpackBaseConfig(false), webpackDevConfig());
const compiler = Webpack(config);
const devServerOptions = Object.assign({}, config.devServer);
console.log('devServerOptions', devServerOptions);
const server = new WebpackDevServer(compiler, devServerOptions);
if (getProcessIdOnPort(port)) {
reject(`端口 ${port} 已被使用`);
return;
} else {
server.listen(
port || 8088,
"0.0.0.0",
() => {
console.log(`Starting server on http://localhost:${port}`);
opn(`http://localhost:${port || 8088}`);
resolve();
},
(err) => {
if (err) console.error("server linsten err--", err);
reject();
}
);
}
});
};
const args = process.argv.splice(2);
const port = args[0] || 8088
buildDev({
port: Number(port)
})
const path = require("path");
const chalk = require("chalk");
const fs = require('fs-extra');
const Webpack = require("webpack");
const WebpackMerge = require("webpack-merge");
const webpackBaseConfig = require("./webpack.common.config");
const { uploadFiles } = require("spark-assets");
const isProd = true;
const { getCdnFolderName } = require("./scripts/utils");
const { SPARK_CONFIG } = require("./scripts/constant");
const HtmlJsToES5Plugin = require("./scripts/plugins/HtmlJsToES5Plugin");
const { DepReporter } =require('spark-log-event');
const sparkConfig = require('../sparkrc');
const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");
const webpackProdConfig = function (cdnFolderName, resPathProd) {
return {
output: {
publicPath: `//yun.duiba.com.cn/spark/v2/${cdnFolderName}/`,
filename: isProd ? "js/[name].[contenthash:8].js" : "js/[name].[contenthash:4].js",
},
resolveLoader: {
modules: ['node_modules', path.resolve(__dirname, './scripts/loaders')]
},
module: {
rules: [
{
test: /sparkrc\.js$/,
exclude: [path.resolve("node_modules")],
use: [
{
loader: 'replaceLoader',
options: {
arr: [
{
replaceFrom: /(MOCK_STATUS: true)|(MOCK_STATUS:true)|("MOCK_STATUS": true)|("MOCK_STATUS":true)/,
replaceTo: '"MOCK_STATUS": false'
},
{
replaceFrom: /(RES_PATH:'\/src\/assets\/')|(RES_PATH: '\/src\/assets\/')|("RES_PATH":"\/src\/assets\/")|("RES_PATH": "\/src\/assets\/")/,
replaceTo: `"RES_PATH":"${resPathProd}/"`
}
]
}
}
]
}
]
},
plugins: [
new Webpack.IgnorePlugin(/[\\/]mock[\\/]/),
new HtmlJsToES5Plugin(),
new ScriptExtHtmlWebpackPlugin({
custom: {
test: /\.js$/,
attribute: 'crossorigin',
value: 'anonymous'
}
}),
new DepReporter()
],
node: {
crypto: 'empty'
}
};
};
const buildProd = async function () {
const cdnFolderName = await getCdnFolderName();
const appPath = process.cwd();
const sparkConfig = require(path.join(appPath, SPARK_CONFIG));
const _webpackProdConfig = await webpackProdConfig(cdnFolderName, sparkConfig.RES_PATH_PROD || '');
//新增 JS_PATH_PROD 用作
let newSparkCfg = Object.assign({}, sparkConfig);
newSparkCfg['JS_PATH_PROD'] = `https://yun.duiba.com.cn/spark/v2/${cdnFolderName}/js`;
const str = `module.exports =${JSON.stringify(newSparkCfg, null, 2)}`;
fs.writeFileSync(path.join(appPath, SPARK_CONFIG), str);
return new Promise((resolve, reject) => {
const config = WebpackMerge(webpackBaseConfig(isProd), _webpackProdConfig);
const compiler = Webpack(config);
compiler.run(async (error, stats) => {
if (error) {
return reject(error);
}
console.log(
stats.toString({
chunks: false, // 使构建过程更静默无输出
colors: true, // 在控制台展示颜色
})
);
console.log(`${chalk.yellow("打包成功, 等待上传")}\n`);
// await uploadFiles(config.output.path, '', cdnFolderName);
await uploadFiles(config.output.path, '', cdnFolderName, /.map$/);
// 上传map到不同路径,避免泄漏源码
await uploadFiles(
config.output.path + "/js",
'js/map_123_map',
cdnFolderName,
/.(js|css|css\.map)$/
);
resolve();
});
});
};
buildProd();
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@src/*": ["src/*"]
}
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
module.exports = {
"data": 3,
"success": true
}
\ No newline at end of file
module.exports = {
"data": "<p>以下是游戏规则:手速要快,点击红包雨。。333。。。。。。。。。。。。。。。。。。。。11111111111111sadasdadadsad5555555557777777777799999999999911111111111111111111111222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333311111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333331111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333</p>",
"success": true
}
\ No newline at end of file
const rule = require("./common/rule");
const drawNum = require("./common/drawNum");
const proxy = {
"GET /projectRule.query": rule,
"GET /drawNum.query": drawNum
};
module.exports = proxy;
This diff is collapsed.
{
"name": "temp_domcanvas",
"version": "3.4.4",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development node ./config/webpack.dev.config.js",
"imgmin": "node ./config/scripts/assets/index.js imgmin",
"imgup": "node ./config/scripts/assets/index.js imgup",
"imgminup": "node ./config/scripts/assets/index.js imgmin imgup",
"prod": "cross-env NODE_ENV=production node ./config/webpack.prod.config.js",
"build": "cross-env NODE_ENV=production node ./config/scripts/assets/index.js imgmin imgup && node ./config/webpack.prod.config.js"
},
"dependencies": {
"@spark/api-base": "^2.0.7",
"@spark/projectx": "^2.0.5",
"@spark/ui": "^2.0.8",
"@spark/utils": "^2.0.17",
"axios": "^0.19.2",
"css-loader": "^3.6.0",
"duiba-utils": "^1.0.2",
"history": "^4.10.1",
"mobx": "^6.2.0",
"mobx-react": "^7.1.0",
"postcss-loader": "^3.0.0",
"prettier": "^2.0.5",
"qs": "^6.9.4",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-router-dom": "^5.2.0",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0",
"spark-utils": "^0.0.12",
"style-loader": "^1.2.1"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-decorators": "^7.13.15",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"autoprefixer": "^9.8.6",
"babel-loader": "^8.2.2",
"chalk": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.3",
"eslint-loader": "^4.0.2",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "^4.5.1",
"less": "^4.1.0",
"less-loader": "^7.2.1",
"mini-css-extract-plugin": "^1.3.4",
"mocker-api": "^2.7.5",
"mockjs": "^1.1.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-px2rem-exclude": "0.0.6",
"progress-bar-webpack-plugin": "^2.1.0",
"script-ext-html-webpack-plugin": "^2.1.5",
"spark-assets": "^1.1.6",
"spark-log-event": "^1.0.4",
"url-loader": "^4.1.1",
"webpack": "^4.43.0",
"webpack-cli": "^4.3.1",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2"
}
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>活动标题</title>
<script src="//yun.duiba.com.cn/spark/v2/spark.base.fz.wxpollyfill.js"></script>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="//yun.duiba.com.cn/h5/lib/zepto.min.js"></script>
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge2043.min.js" crossorigin="anonymous"></script>
<script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
<script>
function getApp() {
return {
cloud: {},
cloudName: "clientTemplate2C",
requestType: "mock"
}
}
var CFG = CFG || {};
CFG.projectId = location.pathname.split('/')[2] || '1';
function getUrlParam(name) {
var search = window.location.search;
var matched = search
.slice(1)
.match(new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'));
return search.length ? matched && matched[2] : null;
}
CFG.appID = '${APPID}';
if (!getUrlParam("appID")) {
alert("【警告】检测到活动url中没有appID参数\n缺少该参数会导致埋点、分享、app信息获取错误。")
}
</script>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{"proName":"fyge-study-spark","proDesc":"","proPath":"/Users/yucheng/Desktop/fyge-study-spark","createTime":1657074315119}
const page = 'a'
module.exports ={
"OUTPUT_DIR": "dist",
"SOURCE_DIR": "src",
"TEMP_DIR": "./.temp",
"ENTRY": "src/app.jsx",
"TEMPLATE": "./public/index.html",
"API_MOCK": true,
"PX2REM": true,
"IMAGE_Q1": 0.6,
"IMAGE_Q2": 0.8,
"RES_PATH": "/src/assets/",
"RES_PATH_PROD": "//yun.duiba.com.cn/spark/v2/temp_domcanvas/1636340485548",
"JS_PATH_PROD": "https://yun.duiba.com.cn/spark/v2/temp_domcanvas/1636340494241/js"
}
\ No newline at end of file
const apiCfg = {
getRule:`projectRule.query`,
doJoin: {
uri: `join.do`,
method: "post"
},
}
export default apiCfg;
import apiCfg from './apicfg';
import {getPxToken} from "@spark/projectx";
import {callApi} from '@spark/api-base'
import {Toast} from '@spark/ui'
import {isFromShare, newUser} from 'duiba-utils';
let mergeData = {
user_type: newUser ? '0' : '1',
is_from_share: isFromShare ? '0' : '1',
}
const apiList = {
...apiCfg
}
const API = generateAPI(apiList);
export default API;
function getRequestParams(value) {
if (typeof value === 'string') {
return {
uri: value,
method: 'get'
}
} else if (typeof value === 'object') {
const {uri, method = 'get', headers, withToken, secret, secretKey, contentType = 'form'} = value;
return {
uri,
method,
headers,
withToken,
secret,
secretKey,
contentType,
}
} else {
console.error('getRequestParams: 传参有误');
}
}
function generateAPI(apiList) {
const api = {};
for (let key in apiList) {
let value = apiList[key];
const {method, uri, headers: mHeaders, withToken, secret, secretKey, contentType} = getRequestParams(value);
api[key] = async (params = {}, headers) => {
let token;
if (withToken) {
try {
token = await getPxToken();
} catch (e) {
Toast('星速台token获取失败,***请补全该处理逻辑***');
return;
}
}
let mergedHeaders = {...mHeaders, ...headers}
if (withToken && token) {
params.token = token;
}
params = {...params, ...mergeData};
const result = await callApi(uri, params, method, mergedHeaders, false, secret, secretKey, contentType)
.catch(e => {
//捕获网络异常
Toast((e.message || '网络异常') + ' ***请补全该处理逻辑***');
});
if (result) {
//判断接口错误
if (!result.success) {
Toast((result.message || '接口错误') + ' ***请补全该处理逻辑***');
}
//返回整个结果
return result;
}
}
}
return api;
}
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./app.less";
import Modal from './modal/modal';
import MD from '../MD';
// MD();
import RouterConfig from "@src/router";
//此处为spark-cli动态生成
class App extends Component {
render() {
return (
<div>
<RouterConfig />
<Modal />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
* {
margin: 0;
padding: 0;
}
html,
body {
font-size: 24px;
width: 100%;
height: 100%;
overflow: hidden;
top: calc((100% - 1624px)/2);
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
import React, { Component } from "react";
import './modal.less';
import { observer } from 'mobx-react';
import modalStore from '../store/modal';
import { toJS } from 'mobx';
export const cfg = {
};
@observer
class Modal extends Component {
constructor(props) {
super(props);
}
componentDidMount() { }
render() {
const list = toJS(modalStore.popList);
if (!list.length) {
//TODO:此处根据需要自行修改
document.body.style.overflow='auto';
return <section></section>;
}
let PopUp, popData, PopUpMulti, popUpMultiData;
if (list.length > 1 && list[list.length - 1].isMulti == true) {
const popObj2 = list[list.length - 1];
PopUpMulti = cfg[popObj2.key];
popUpMultiData = popObj2.data;
}
const popObj = list[0];
PopUp = cfg[popObj.key];
popData = popObj.data;
if (PopUp || PopUpMulti) {
document.body.style.overflow='hidden';
}
return <section className="modal-hoc-bg" style={{
zIndex: !!modalStore.popList.length ? 1000 : -1,
display: !!modalStore.popList.length ? 'block' : 'none'
}}>
{PopUp && <PopUp popData={popData} />}
{PopUpMulti && <section className="modal-hoc-bg" style={{
zIndex: !!modalStore.popList.length ? 1000 : -1,
display: !!modalStore.popList.length ? 'block' : 'none'
}}><PopUpMulti popData={popUpMultiData} />
</section>}
</section>;
}
}
export default Modal;
\ No newline at end of file
.modal-hoc-bg {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1000;
}
\ No newline at end of file
//全部事件
export const GDiapatcher = new FYGE.EventDispatcher();
\ No newline at end of file
'use strict';
import React, { Component } from 'react';
import API from '../../api/index.js';
import './canvasScene.less';
import { GDiapatcher } from './GDiapatcher.js';
import { RES_PATH } from '../../../sparkrc';
//引擎sdk <script src="//yun.duiba.com.cn/db_games/libs0924/fyge2014.min2d.js" crossorigin="anonymous"></script>
export default class CanvasScene extends Component {
/**
*
* @param {*} props
*/
constructor(props) {
super(props);
this.canvasRef = React.createRef();
this.state = {
}
}
componentDidMount() {
// this.props.onRef(this);
var canvas = this.canvasRef.current;
//canvas画布实际尺寸,
canvas.width = document.body.clientWidth * (window.devicePixelRatio || 1)
canvas.height = document.body.clientHeight * (window.devicePixelRatio || 1)
//建舞台
var stage = new FYGE.Stage(
canvas,
750,//设计宽度,按设计搞给的就行
1624,//设计高度
document.body.clientWidth,//显示宽度
document.body.clientHeight,//显示高度
FYGE.RENDERER_TYPE.CANVAS,
false//舞台是否居中,false左上置顶,true小于1624的视窗会上下平均裁切
);
//鼠标事件
var mouseEvent = stage.onMouseEvent.bind(stage);
canvas.addEventListener("touchstart", mouseEvent, false);
canvas.addEventListener('touchmove', mouseEvent, false);
canvas.addEventListener('touchend', mouseEvent, false);
//stage初始化
stage.addEventListener(FYGE.Event.INIT_STAGE, this.initScene, this)
//挂舞台指向
this.stage = stage;
//循环
const self = this;
(function loop() {
FYGE.Tween.flush()
stage.flush();
self.requestID = window.requestAnimationFrame(loop);
})()
}
async initScene() {
var stage = this.stage;
//添加个背景矢量图
stage.addChild(new FYGE.Graphics())
.beginFill(0x000000, 0.7)
.drawRect(0, 0, 750, 1624)
.endFill()
//单图纹理
var texture = await new Promise((r) => {
FYGE.GlobalLoader.loadImage((s, image) => {
r(FYGE.Texture.fromImage(image))
}, RES_PATH + "aa.png")
})
//纹理图片
var sp = stage.addChild(new FYGE.Sprite(texture))
.addEventListener(FYGE.MouseEvent.CLICK, () => { console.log("点击了") }, this)
sp.position.set(200, 500);//位置
sp.scale.set(0.5, 0.5)//缩放
sp.anchorTexture.set(0.5, 0.5)//贴图锚点,改变初始坐标,0到1
//遮罩
var mask = stage.addChild(new FYGE.Graphics())
.beginFill(0x000000)
.drawRect(100, 500, 400, 300)
.endFill()
sp.mask = mask;
//来个动画
FYGE.Tween.get(sp)
.to({ rotation: 360 }, 5000)
.to({ scaleX: 1.1, scaleY: 1.1 }, 3000)
.to({ scaleX: 1, scaleY: 1 }, 300)
.to({ x: 400 }, 1000)
.call(() => { console.log("动画结束") })
//异步渲染网络图片
stage.addChild(FYGE.Sprite.fromUrl("https://img.alicdn.com/imgextra/i4/2275046294/O1CN01avEmL01wMhS5Wxd63_!!2275046294-2-miniprogram.png"))
.position.set(300, 700)
//文本
var text = stage.addChild(new FYGE.TextField())
text.size = 30//字号
text.text = "亲吻青蛙撒大"//内容
text.textAlign = FYGE.TEXT_ALIGN.CENTER//居中
text.textWidth = 400//居中需要设置文本固定宽度才有效
text.position.set(100, 1000)
var a = { x: 0 }
FYGE.Tween.get(a, {
onChange: () => {//缓动改变时监听
text.text = "亲吻青蛙撒大" + Math.round(a.x)
}
})
.to({ x: 10000 }, 100000)
//位图文本chapterNum0
var textures = await new Promise((r) => {
var t = {};
let count = 0;
for (var i = 0; i < 10; i++) {
let c = i;
FYGE.GlobalLoader.loadImage((s, image) => {
t["" + c] = FYGE.Texture.fromImage(image);
if (++count == 10) r(t)
}, RES_PATH + "chapterNum" + c + ".png")
}
})
console.log(textures)
var bitmapText = stage.addChild(new FYGE.BitmapText(textures))
bitmapText.text = "12345"
bitmapText.x = 300
bitmapText.y = 200
bitmapText.textAlign = "center"
bitmapText.verticalAlign = "middle"
bitmapText.gap = -6
var b = { x: 0 }
console.log(bitmapText)
// FYGE.Tween.get(b, {
// onChange: () => {//缓动改变时监听
// bitmapText.text = "" + Math.round(b.x)
// }
// })
// .to({ x: 10000 }, 100000)
//帧动画
var texArr = []//需要纹理的数组
for (var i = 0; i <= 15; i++) texArr.push(FYGE.Texture.fromUrl(RES_PATH + "hor_ele1_" + i + ".png"));
for (var i = 14; i >= 1; i--) texArr.push(FYGE.Texture.fromUrl(RES_PATH + "hor_ele1_" + i + ".png"));//反方向
var frameAni = stage.addChild(new FYGE.FrameAni(texArr))
frameAni.position.set(200, 900)
frameAni.mouseEnable = frameAni.mouseChildren = false;//鼠标事件去掉,可穿透
frameAni.play(0)//循环播放
//svga动画 sdk <script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
SvgaParser.loadSvga(RES_PATH + "小贱成年常态.svga", (v) => {
stage.addChild(new FYGE.MovieClip(v)).y -= 600
})
//lottie动画(文件全)
FYGE.GlobalLoader.loadJson((s, json) => {
var l = stage.addChild(new FYGE.Lottie(json))
l.play()
l.x += 200
}, RES_PATH + "click_action_11.json")
//lottie转svga播放
FYGE.GlobalLoader.loadJson((s, json) => {
console.log(Date.now())
var m = stage.addChild(new FYGE.MovieClip(FYGE.lottieToSvgaData(json)))
console.log(Date.now())
m.mouseChildren = m.mouseEnable = false;
m.lockStep = true;//帧率60除不尽的,只能用这个
m.startAniRange(undefined, undefined, 2, () => {
stage.removeChild(m)
})
}, RES_PATH + "yaoqinghan_tianmao.json")
//按钮
stage.addChild(new FYGE.Button(texture))
.addEventListener(FYGE.MouseEvent.CLICK, () => { console.log("点击了按钮") }, this)
.position.set(0, 1100)
//滚动视图
var scroll = stage.addChild(new FYGE.ScrollPage(640, 656, 100, true, false))
scroll.position.set(500, 1100)
scroll.view.addChild(new FYGE.Sprite(texture))//在view里面添加
scroll.maxDistance = 1000
setTimeout(() => { scroll.scrollTo(200, 2000) }, 2000)
//滚动列表
var list = new FYGE.ScrollList(class extends FYGE.Sprite {
constructor() {
super()
this.txt = new FYGE.TextField();
this.txt.size = 50;
this.txt.fillColor = "#ff0000";
this.addChild(this.txt)
}
initData(id, data) {
if (id < 0 || !data) return
this.txt.text = data + ""
}
}
, 100, 60, 100, 400, true)
list.x = 100;
list.y = 300;
list.updateData([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], true)//更新数据,true覆盖原先数据
stage.addChild(list);
//shape
// var s = stage.addChild(new FYGE.Shape())
// s.beginFill(0, 0.7)
// s.moveTo(0, 0);
// s.lineTo(0, 1624);
// s.lineTo(750, 1624);
// s.lineTo(750, 0);
// s.lineTo(0, 0);
// s.moveTo(300, 300)
// s.drawRoundedRect(300, 100, 200, 100, 1111)
// s.endFill()
//画线
var s = stage.addChild(new FYGE.Shape())
s.beginStroke(0, 3)
s.moveTo(10, 10);
s.lineTo(10, 500);
s.lineTo(200, 500);
s.lineTo(200, 10);
s.lineTo(10, 10);
s.endStroke()
}
jumpScene() {
mHistory.push({ pathname: '/a' });
}
componentWillUnmount = () => {
//有
GDiapatcher.removeAllEventListener();
//Tween都移除,
FYGE.Tween.removeAllTweens()
//计时器取消
window.cancelAnimationFrame(this.requestID);
//舞台销毁
this.stage.destroy();
}
render() {
return (
<div className="canvas-box" >
<canvas id="canvas" ref={this.canvasRef}></canvas>
</div>
);
}
}
.canvas-box {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
// background-size: 100%;
// background-position: center;
// background-image: url("https://yun.duiba.com.cn/长城wey/选择车辆背景.jpg");
}
#canvas {
width: 100%;
height: 100%;
}
@RES_PATH: '/src/assets/';
.sparkBg(@value) {
background: url("@{RES_PATH}@{value}") no-repeat top left / 100% 100%;
}
\ No newline at end of file
import CanvasScene from '@src/pages/canvasScene/CanvasScene.jsx';
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { createHashHistory } from "history";
const history = createHashHistory();
class RouterConfig extends React.Component {
render() {
return (
<Router history={history}>
<Switch>
<Route exact path="/" component={CanvasScene} />
</Switch>
</Router>
)
}
}
export default RouterConfig;
import { makeAutoObservable } from 'mobx';
import API from '../api/index';
const store = makeAutoObservable({
ruleInfo: '',
setRule(ruleInfo) {
this.ruleInfo = ruleInfo
},
async initRule() {
// 模拟获取远程的数据
const { data } = await API.getRule();
this.setRule(data)
}
})
export default store;
\ No newline at end of file
import { makeAutoObservable,toJS } from 'mobx';
//此处配置页面的优先级,越大优先级越高
// PopIndex:11
const modalIndex = {
}
const modalStore = makeAutoObservable({
popList: [],
/**
*
* @param {*} key 弹窗名,一般是类名的字符串
* @param {*} data 需要传递的数据,弹窗中使用 const {popData} = props; 获取
* @param {*} isMulti 是否是二级弹窗,在不关闭已有弹窗的基础上,弹出当前弹窗。注意,如果是二级弹窗,关闭时必须传key
*/
pushPop(key, data,isMulti=false) {
if (this.popList.length) {
let cacheList = this.popList.slice();
cacheList.push({ key, data,isMulti });
cacheList = cacheList.sort((a, b) => ((modalIndex[b.key] ? modalIndex[b.key] : 10) - (modalIndex[a.key] ? modalIndex[a.key] : 10)))
this.popList.clear();
this.popList.push(...cacheList);
} else {
this.popList.push({ key, data,isMulti });
}
// console.log("this.popList:::",toJS(this.popList));
},
closePop(key) {
if (key) {
let cacheList = this.popList.slice();
cacheList = cacheList.filter(obj => (obj.key != key));
this.popList.clear();
this.popList.push(...cacheList);
} else {
this.popList.shift();
}
},
closePopAll() {
this.popList.clear();
}
});
export default modalStore;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment