在线三角形生成器
通过本文,你将学到如下知识:
- 快速入门vue 3.2的核心API知识
- 掌握最新浏览器实现的复制粘贴的clipboard API
- 按需引入element plus
- vite 的一些入门配置
- 正则表达式以及typescript的类型
- less语法
- element plus 国际化
本示例的实现灵感来自于徐小夕大佬的在线三角形生成器--文章和在线三角形生成器--示例,感谢大佬提供的灵感。
快速创建一个vite项目
参考文档官网vite。我们可以快速创建一个项目:
# npm 6.x
npm init vite@latest triangle --template vue
# npm 7+, extra double-dash is needed:
npm init vite@latest triangle -- --template vue
# yarn
yarn create vite triangle --template vue
接下来,我们需要再额外添加一些依赖。
yarn add unplugin-vue-components element-plus less
unplugin-vue-components是element plus提供的一个按需引入实现的插件。然后修改vite.config.js的代码如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from "unplugin-vue-components/vite"
import { ElementPlusResolver } from "unplugin-vue-components/resolvers"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
Components({
resolvers:[ElementPlusResolver()]
})
],
base:"./"
})
全是照着element plus官方文档来一步一步操作的。
接下来,在main.js中引入element plus的样式文件:
import "./style/reset.less"
import 'element-plus/dist/index.css'
其中reset.less的代码如下:
body,h1,img,h2,h3,h4,h5,h6,p {
margin: 0;
padding: 0;
}
.app {
width: 100vw;
height: 100vh;
background: linear-gradient(135deg,#e0e0e0 10%,#f7f7f7 90%);
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-y: auto;
overflow-x: hidden;
}
::-webkit-scrollbar {
width: 0;
height: 0;
}
如此一来,准备工作算是完成了,接下来,我们就来一步一步的实现。
实现的工具函数
在src目录下创建一个utils目录,然后新建一个utils.ts文件,里面写上如下代码:
export const getTriangleStyle = (direction:string,w:number,h:number,color:string) => {
const style = {
"top":{
"borderColor":`transparent transparent ${color} transparent`,
"borderWidth":`0 ${w / 2}px ${h}px ${w / 2}px`
},
"bottom":{
"borderColor":`${color} transparent transparent transparent`,
"borderWidth":`${h}px ${w / 2}px 0 ${w / 2}px`
},
"left":{
"borderColor":`transparent ${color} transparent transparent`,
"borderWidth":`${h / 2}px ${w}px ${h / 2}px 0`
},
"right":{
"borderColor":`transparent transparent transparent ${color}`,
"borderWidth":`${h / 2}px 0 ${h / 2}px ${w}px`
}
}
return style[direction];
}
这个工具函数其实也就是实现三角形的方向切换问题。
页面分析
接下来,我们来看页面的整体。其实包含了五大部分,如下图所示:
即:
- 头部组件(包含标题组件)
- 操作样式的表单
- 预览模块
- 代码编辑器
- 底部信息
头部组件
我们一部分一部分的来看,首先是头部组件的实现,头部组件只是包含一个标题组件,所以我们先来看标题组件的实现。如下所示:
template部分:
{{ content }}
js部分:
就这么一点代码,我们就需要了解vue3.x的四个知识点。
- vue可以为script标签添加setup,从而使得整个代码块都在setup钩子函数作用域中,setup钩子函数相当于vue2.x的beforeCreated和created的合并,也是vue3.x composition API 的入口函数。
- 导入
defineProps
就可以定义vue的props单向数据流。这里定义了2个字段,即level
和content
。顾名思义,level就是用于动态组件的,我们实际上就是封装一个动态组件,组件的标签是h1~h6
,level的默认值是1。它的类型可以使字符串或者数值。而content就是字符串,被用作插槽的备用内容。 - 动态组件component,通过绑定is属性可以知道组件名。
- 插槽slot。
正好,我们的头部就用到了这个标题组件,接下来我们来看头部组件即Header
组件的实现。
template部分:
趣谈前端|在线三角形生成器
js部分:
style部分:
可以看到头部组件,我们使用弹性盒子布局,让组件垂直水平居中,字体颜色为#535455
。在js部分,我们直接导入了前面我们封装的标题组件。在模板部分,我们直接使用了header元素包裹这个标题组件。并且添加了一个插槽元素。
这样一来,我们的头部组件部分就完成了,比较简单。
表单部分
接下来我们来看表单部分。
template部分:
{{ item.label }}
js部分:
style部分:
在这里,我们分析页面的部分,我们知道,我们需要用到单选框分组组件,单选框组件,颜色选择器组件,表单组件,国际化配置组件(element plus新增的elConfigProvider,个人理解设计借鉴了react的Provider组件),滑块组件。单选框组件用于修改三角形的方向,滑块组件用于配置三角形的宽高以及旋转角度,而颜色选择器组件用于配置三角形的背景颜色。所以我们定义了如下对象:
form:{
direction:"top",//方向
width:60,//宽度
height:60,//高度
color:"#2396ef",//背景色
rotate:0 //旋转角度
},
我们使用vue的reactive方法来定义响应式数据。由于颜色选择器默认是英文,所以我导入了element plus的中文包。即:
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
然后再颜色选择器中,添加el-config-provider
组件包裹颜色选择器。实际上我这里只是单独设置颜色选择器的中文包,这个组件应该是包裹在根元素组件App
的。然后我们使用了defineEmits
发出一个事件给父组件使用。如下:
const emit = defineEmits(["on-change"]);
watch(() => state.form,(val) => {
emit("on-change",val);
},{ deep:true,immediate:true })
我们使用watch
方法监听表单数据对象,并且提供了配置选项,也就是说该组件在创建的时候就会立即执行一次该方法,然后发出一个on-change
事件,将form
表单数据给传给父组件使用。
预览组件
接下来,我们来看预览组件的实现:
template部分:
js部分:
style部分:
可以看到预览组件就2个元素,其中父元素就是我们最外层的盒子元素,盒子元素通过设置渐变,才会出现那样的效果。然后我们的三角形元素,它的基本样式还是有一些不会变动的,所以我们写在样式当中,变动的样式我们才定义在数据中。可以看到,我们通过接受父组件穿过来的formData表单数据对象,然后需要进行样式对象的规范化处理,这才是我们监听函数的意义所在:
watch(() => props.formData,(val) => {
const { direction,color,width,height,rotate } = val;
state.style = { ...getTriangleStyle(direction,width,height,color),transform:`rotate(${rotate}deg)`};
},{ deep:true,immediate:true })
我们也是使用了immediate
选项,会让组件在创建的时候就立即调用一次,然后我们通过对象解构拿到父组件出来的props数据,并且修改定义在reactive
方法实现的响应式数据中。然后再绑定到元素的style
属性上。
根组件
接下来是第三部分,代码编辑器的部分,我们是直接写在根组件APP.vue
中的,可以看到代码编辑器的部分包含三块。
- 标题
- 复制代码按钮
- 显示代码的文本框(禁用)
接下来,我们就来看一下根组件的代码吧。
template部分:
CSS代码
复制代码
inspired by 在线三角形样式生成器
更多示例尽在我的个人项目集合 中。
js部分:
style样式部分:
由于兼容了移动端布局,所以样式代码看起来有点多。但整体就是利用媒体查询来调整一下。这里我们用到了element plus的ElRow,ElCol,ElInput,ElHeader,ElButton,ElFooter,ElLink,ElMessageBox
组件。template的组件元素应该是很好理解的,包含的五个部分都写进去了。
tips:这里需要提醒一下,写vue3.x的语法需要安装
volar
插件。
接下来我们来看js部分,js部分其实就是导入了需要使用的组件,然后接受了子组件传来的表单数据。并且我们获取到了三角形元素的css代码,然后渲染到文本框中去。这里我们操作css样式获取到了元素的css代码字符串,然后利用正则表达式处理了一下,最后才能得到我们实际显示的那样保持规范化的缩进而显示的代码。
我们做的一系列正则表达式的匹配,就是为了让代码显示保持合格的缩进。
比如添加\n
换行符,css样式属性名的前面添加一段空白。这些都没什么好说的。这里比较有意思的实现,就是复制代码的实现:
const onCopyCodeHandler = () => {
// `navigator.clipboard.writeText` not working in wechat browser.
if(navigator.userAgent.toLowerCase().indexOf('micromessenger') === -1){
navigator.clipboard.writeText(state.code).then(() => confirm())
}else{
const input = document.createElement("input");
input.value = state.code;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
input.remove();
confirm();
}
}
在微信浏览器端不知道是不是因为内置view组件的实现原因,并不支持clipboard
API。我们通过获取到navigator下的clipboard属性,它就是一个剪贴板对象,然后我们可以调用writeText
方法,就可以往剪贴板中写入内容。也就实现了用户鼠标复制需要复制的内容的实现,该方法返回一个promise,在then方法中,我们弹出一个提示框,用于提示用户代码内容已经复制了。
而在微信浏览器端,我们还是通过创建一个input元素,将复制的内容赋给input元素,然后设置选中,调用document.execCommand("copy")
事件。最后弹出提示。如此一来,我们的三角形生成器就这样实现了。
最后
如果觉得本文能让你学到东西,望不吝啬点个赞。详细源码可以查看这里。最后感谢大家的阅读。