演示面板
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地址上;与此同时,新的代码会被解析并渲染到右侧面板