Skip to content

演示面板

Jiess Playground是一个用于演示Jiess语法的在线工具

示例代码

查看示例

完整代码

这是一个纯原生Demo,并使用Jiess语法所构建:

html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>Jiess 演示面板</title>
		<link rel="stylesheet" href="./styles/common.css" />
		<link rel="stylesheet" href="./styles/parent.css" />
		<!-- 引入工具库 -->
		<script src="//unpkg.com/@jiess/utils"></script>
		<!-- Import Vue 3 -->
		<script src="//unpkg.com/vue@3"></script>
		<!-- 引入Prettier -->
		<script src="//unpkg.com/prettier@latest/standalone.js"></script>
		<!-- 引入Babel Parser -->
		<script src="//unpkg.com/prettier@3.2.5/plugins/babel.js"></script>
		<script src="//unpkg.com/prettier@3.2.5/plugins/estree.js"></script>
		<!-- 工具方法直接注入父级环境 -->
		<script src="./common/utils.js"></script>
	</head>

	<body>
		<div id="root" />
		<script type="importMap">{
			"imports":{
				"@jiess/plus/vue3":"https://unpkg.com/@jiess/plus/es/envVue3.js",
				"@jiess/plus":"https://unpkg.com/@jiess/plus/es/JiessCore.js"
			}
		}</script>
		<script type="module">
			import JiessEnv from '@jiess/plus/vue3';
			import { $entry, $val, $ref } from '@jiess/plus';
			// 初始化安装Jiess(JiessEnv为vue3的环境适配器)
			const { JiessComponent } = $entry(JiessEnv, Vue);
			// setup函数构建渲染节点
			function setup() {
				const search = location.search.slice(1);
				const query = JiessTools.querystring.parse(search);
				const { type = 'vue3', opts = 'vue2,vue3,react' } = query;
				const curTab = $ref(type);
				this.add(
					this.render({ class: 'container' },
						this.render({ is: 'header' },
							this.render({
								is: 'a',
								class: 'title',
								target: '__blank',
								href: 'https://jiess.net/about/playground.html'
							}, `Jiess文档`),
							this.render({
									is: 'select',
									value: $val(curTab, 'value'),
									onChange: e => {
										curTab.value = e.target.value;
										location.search = `type=${curTab.value}&opts=${opts}`;
									}
								},
								opts.split(',').map(value => {
									return this.render({ is: 'option', value }, value)
								})
							)
						),
						this.render({
							is: 'iframe',
							style: { width: '100%' },
							src: $val(curTab, 'value', type => {
								return `/htmls/${type}.html${location.hash}`
							})
						})
					)
				)
			}
			Vue.createApp({
				render: () => Vue.h(JiessComponent, { setup })
			}).mount('#root');
		</script>
	</body>

</html>
html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>vue2 演示</title>
		<link rel="stylesheet" href="./styles/common.css" />
		<link rel="stylesheet" href="./styles/childs.css" />
		<link rel="stylesheet" href="../jiess-base/vue2element/css/base.css" />
		<!-- 引入样式 -->
		<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
		<!-- 引入vue库 -->
		<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
		<!-- 引入组件库 -->
		<script src="https://unpkg.com/element-ui/lib/index.js"></script>
		<!-- 引入Jiess核心库 -->
		<script src="https://unpkg.com/@jiess/plus/umd/envVue2.js"></script>
		<script src="https://unpkg.com/@jiess/plus/umd/JiessCore.js"></script>
		<!-- 引入Jiess工具库 -->
		<script src="//unpkg.com/@jiess/http/umd/JiessHttp.js"></script>
		<script src="//unpkg.com/@jiess/utils"></script>
		<script src="//unpkg.com/@jiess/http/umd/JiessLoading"></script>
		<script src="//unpkg.com/@jiess/utils/jiess-utils/umd/JiessMidder.js"></script>
	</head>

	<body>
		<div id="root"></div>
		<script type="module">
			import {
				$Area,
				$Input,
				$Select,
				$Between,
				$InputNumber,
				$JiessDialog,
				$tanInstance,
				$dialogInstance
			} from '../jiess-base/vue2element/cdn/index.js';
			import setup from './common/index.js';
			Object.assign(window, { $Input, $InputNumber, $Select, $Between });
			const { $component, $entry } = JiessCore;
			// 初始化安装Jiess(JiessEnv为vue2的环境适配器)
			const { JiessComponent } = $entry(JiessEnv, {}, {
				area: $Area,
				$tan: $tanInstance,
				dialog: $dialogInstance
			});
			$component('jiess', JiessComponent);
			new Vue({
				render: h => h(JiessComponent, {
					attrs: {
						setup() {
							// 在项目最外层使用全局弹框组件
							this.add(this.render({ is: $JiessDialog }));
							setup.call(this, { type: 'vue2' })
						}
					}
				})
			}).$mount('#root');
		</script>
	</body>

</html>
html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>vue3 演示</title>
		<link rel="stylesheet" href="./styles/common.css" />
		<link rel="stylesheet" href="./styles/childs.css" />
		<link rel="stylesheet" href="../jiess-base/vue3element/css/base.css" />
		<!-- Import style -->
		<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
		<!-- Import Vue 3 -->
		<script src="//unpkg.com/vue@3"></script>
		<!-- Import component library -->
		<script src="//unpkg.com/element-plus"></script>
		<!-- 引入Jiess核心库 -->
		<script src="https://unpkg.com/@jiess/plus/umd/envVue3.js"></script>
		<script src="https://unpkg.com/@jiess/plus/umd/JiessCore.js"></script>
		<!-- 引入Jiess工具库 -->
		<script src="//unpkg.com/@jiess/http/umd/JiessHttp.js"></script>
		<script src="//unpkg.com/@jiess/utils"></script>
		<script src="//unpkg.com/@jiess/http/umd/JiessLoading"></script>
		<script src="//unpkg.com/@jiess/utils/jiess-utils/umd/JiessMidder.js"></script>
	</head>

	<body>
		<div id="root" />
		<script type="module">
			import {
				$Area,
				$Input,
				$Select,
				$Between,
				$InputNumber,
				$JiessDialog,
				$tanInstance,
				$dialogInstance,
			} from '../jiess-base/vue3element/cdn/index.js';
			import setup from './common/index.js';
			Object.assign(window, { $Input, $InputNumber, $Select, $Between });
			const { $component, $entry } = JiessCore;
			// 初始化安装Jiess(JiessEnv为vue3的环境适配器)
			const { JiessComponent } = $entry(JiessEnv, Vue, {
				area: $Area,
				$tan: $tanInstance,
				dialog: $dialogInstance
			});
			$component('jiess', JiessComponent);
			Vue.createApp({
				render: () => Vue.h(JiessComponent, {
					setup() {
						// 在项目最外层使用全局弹框组件
						this.add(this.render({ is: $JiessDialog }));
						setup.call(this, { type: 'vue3' })
					}
				})
			}).mount('#root');
		</script>
	</body>

</html>
html
<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>react 演示</title>
		<link rel="stylesheet" href="./styles/common.css" />
		<link rel="stylesheet" href="./styles/childs.css" />
		<link rel="stylesheet" href="../jiess-base/react168antd/css/base.css" />
		<link href="https://cdn.bootcdn.net/ajax/libs/antd/5.9.0/reset.css" rel="stylesheet">
		<!-- 引入react库 -->
		<script src="https://cdn.staticfile.org/react/18.2.0/umd/react.development.js"></script>
		<script src="https://cdn.staticfile.org/react-dom/18.2.0/umd/react-dom.development.js"></script>
		<!-- 引入ant-design -->
		<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.9/dayjs.min.js"></script>
		<script src="https://cdn.bootcdn.net/ajax/libs/antd/5.9.0/antd.min.js"></script>
		<!-- 引入Jiess核心库 -->
		<script src="https://unpkg.com/@jiess/plus/umd/envReact.js"></script>
		<script src="https://unpkg.com/@jiess/plus/umd/JiessCore.js"></script>
		<!-- 引入Jiess工具库 -->
		<script src="//unpkg.com/@jiess/http/umd/JiessHttp.js"></script>
		<script src="//unpkg.com/@jiess/utils"></script>
		<script src="//unpkg.com/@jiess/http/umd/JiessLoading"></script>
		<script src="//unpkg.com/@jiess/utils/jiess-utils/umd/JiessMidder.js"></script>
	</head>

	<body>
		<div id="root"></div>
		<script type="module">
			import {
				$Area,
				$Input,
				$Select,
				$Between,
				$InputNumber,
				$JiessDialog,
				$tanInstance,
				$dialogInstance
			} from '../jiess-base/react168antd/cdn/index.js';
			import setup from './common/index.js';
			Object.assign(window, { $Input, $InputNumber, $Select, $Between });
			const { $component, $entry } = JiessCore;
			// // 初始化安装Jiess(JiessEnv为react的环境适配器)
			const { JiessComponent } = $entry(JiessEnv, React, {
				area: $Area,
				$tan: $tanInstance,
				dialog: $dialogInstance
			});
			// 全局注册Jiess组件
			$component('jiess', JiessComponent);
			const container = document.getElementById('root');
			const root = ReactDOM.createRoot(container);
			root.render(React.createElement(JiessComponent, {
				setup() {
					// 在项目最外层使用全局弹框组件
					this.add(this.render({ is: $JiessDialog }));
					setup.call(this, { type: 'react' });
				}
			}));
		</script>
	</body>

</html>
js
// 全局暴露Jiess中常用的内置工具,可以在eval字符串模板中直接使用
const { $ref, $val, $watch, $reactive, $computed, $watchEffect } = JiessCore;
const hashStr = location.hash.slice(1);
const decode = decodeURIComponent(hashStr);
const maps = {
	react: ['ant-design', 'antd'],
	vue2: ['element-ui', 'ELEMENT'],
	vue3: ['element-plus', 'ElementPlus']
};
export default function({ type }) {
	const mapping = maps[type];
	const decodeData = $ref(decode);
	const styleTextarea = $ref({});
	// ------------------------------------------
	this.add(
		this.render({ class: 'container' },
			this.render({ is: 'section', class: 'box' },
				(() => {
					const param = {
						rows: 20,
						is: 'textarea',
						placeholder: '输入代码',
						style: $val(styleTextarea, 'value'),
						onInput: async (e) => {
							// 不论格式是否正确,均允许直接赋值
							let codeStr = decodeData.value = e.target.value;
							JiessTools.debounce1(async () => {
								try {
									codeStr = await parent.$utils.formatCode(codeStr);
									const hashStr = encodeURIComponent(codeStr);
									parent.location.hash = location.hash = hashStr;
									styleTextarea.value = { borderColor: '#3eaf7c' };
									// navigator.clipboard.writeText(hashStr);
								} catch (error) {
									console.warn(error);
									this.add('代码格式化有误,请排查!!!');
									styleTextarea.value = { borderColor: 'red' };
								}
							}, 1000)
						}
					};
					// vue和react对textare赋值的差异性
					if (type === 'react') {
						param.value = $val(decodeData, 'value');
					} else {
						param.children = $val(decodeData, 'value');
					}
					return this.render(param);
				})(),
				this.render({ class: 'right-preview' },
					this.render({
						is: 'jiess',
						setup() {
							this.add(
								this.render({
									is: 'jiess',
									setup: $val(decodeData, 'value', (codeStr) => {
										return function(...args) {
											try {
												eval(`(${codeStr})`).call(this, ...args);
												styleTextarea.value = { borderColor: '#3eaf7c' };
											} catch (error) {
												console.warn(error);
												this.add('代码解析有误,请排查!!!');
												styleTextarea.value = { borderColor: 'red' };
											}
										}
									})
								})
							)
						}
					})
				)
			)
		),
		this.render({ style: { fontSize: '13px', color: 'gray' } },
			this.render({ is: 'p' },
				`* 当前为${type}环境,使用${mapping[0]},通过${mapping[1]}获取相关的UI组件;使用JiessCore获取Jiess内置模块(部分常用内置模块已挂载全局)`),
			this.render({ is: 'p' },
				'* 上下文注入area,$tan,dialog工具,且已应用全局弹框组件;全局引入JiessTools工具库,JiessMidder中介者,JiessHttp请求器,JiessLoading加载器'),
		)
	)
}
js
const prettierConfig = {
	parser: "babel",
	plugins: prettierPlugins,
	// 一行最多多少个字符
	"printWidth": 180,
	// 指定每个缩进级别的空格数
	"tabWidth": 2,
	// 使用制表符而不是空格缩进行
	"useTabs": true,
	// 在语句末尾打印分号
	"semi": true,
	// 使用单引号而不是双引号
	"singleQuote": true,
	// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
	"quoteProps": 'as-needed',
	// 在JSX中使用单引号而不是双引号
	"jsxSingleQuote": false,
	// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
	"trailingComma": 'es5',
	// 在对象文字中的括号之间打印空格
	"bracketSpacing": true,
	// jsx 标签的反尖括号需要换行
	"jsxBracketSameLine": false,
	// 在jsx中把'>' 是否单独放一行
	"bracketSameLine": false,
	// 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x
	"arrowParens": 'always',
	// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
	"rangeStart": 0,
	"rangeEnd": Infinity,
	// 指定要使用的解析器,不需要写文件开头的 @prettier
	"requirePragma": false,
	// 不需要自动在文件开头插入 @prettier
	"insertPragma": false,
	// 使用默认的折行标准 always\never\preserve
	"proseWrap": 'preserve',
	// 指定HTML文件的全局空格敏感度 css\strict\ignore
	"htmlWhitespaceSensitivity": 'css',
	// Vue文件脚本和样式标签缩进
	"vueIndentScriptAndStyle": false,
	// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
	"endOfLine": 'lf'
};
// ==================================================
var $utils = {
	formatCode(code) {
		return prettier.format(code, prettierConfig);
	}
}
css
body {
  margin: 0;
}
a {
  text-decoration: none;
}
css
.container {
  display: flex;
  min-height: 600px;
  flex-direction: column;
}
.container .box {
  display: flex;
  flex: 1;
}
.container .box textarea {
  outline: none;
  color: #3eaf7c;
  font-size: 18px;
  margin-right: 12px;
  width: calc(50% - 6px);
  font-family: 微软雅黑;
}
.container .box .right-preview {
  border: 1px solid #3eaf7c;
  background-color: white;
  flex: 1;
}
css
body {
  background-color: #f3f4f6;
}
.container {
  height: 100vh;
  display: flex;
  flex-direction: column;
}
.container header {
  color: white;
  padding: 12px;
  font-size: 18px;
  font-weight: bold;
  display: flex;
  background-color: #3eaf7c;
}
.container header .title {
  color: white;
  margin-right: 6px;
}
.container header .title:hover {
  color: wheat;
}
.container iframe {
  flex: 1;
  border: 0;
}

结构说明

项目的入口为index.html,进入页面时会从地址栏读取type——当前环境;opts——当前代码所支持的环境; 默认环境为vue3,默认支持全部vue/react环境(及下拉切换选项)

通过左上角的下拉框用于展示当前所处环境,同时也可以切换其他的渲染环境,切换过程中, 地址栏会从新记录新的环境变量,便于F5刷新后停留在所切换的环境

用法说明

Jiess Playground使用url(#后的hash部分)记录代码内容,所以每个面板会有长长的url

面板编辑区是一个单纯的textarea输入框,所以不像通用编辑器一样灵活,但其使用了prettier工具, 可以在页面刷新时,自动的格式化面板中的代码

内部流程

在编辑区输入内容时,会使用prettier工具,自动格式化代码,然后将格式化后的代码转换处理为字符串, 将其记录到url地址上;与此同时,新的代码会被解析并渲染到右侧面板