ps:好久没更新了…还是要看看vue的文档更新一些内容啦
响应式api
vue3的响应式api真的太多了,就更新一些常用的吧
ref
//接受一个内部值,返回一个响应式的、可更改的 ref 对象
const count=ref<number>(0)
count.value+=1 //更改值
computed
//设置只读
const user = ref([
{ id: 1, name: 'chen', age: 18 },
{ id: 2, name: 'wang', age: 19 },
{ id: 3, name: 'li', age: 24 },
])
//返回年龄大于18的成员
const adultUser = computed(() => user.value.filter((item) => item.age > 18))
//可写计算属性
reactive
watchEffect
watch
状态管理
这么多东西我这么记得住?
pinia
vuex
状态管理对比
工具类
node_modules文件
删除文件:
该文件夹包含大量node安装包可以使用rimraf
npm install rimraf -g
rimraf node_modules //删除该文件夹
安装文件:
安装使用淘宝镜像:npm config set registry https://registry.npm.taobao.org
查看淘宝镜像:npm config get registry
安装文件:yarn install
案例篇
菜单
注:最好将菜单挂载到body,这样不会出现层级问题
html--
<Card :status="status" :pX="pX" :pY="pY" :list="menuRef" />
<nav>
<li v-for="item in data" :key="item" @click.right="rightMenu($event, item)">
{{ item }}
</li>
</nav>
js--
import { ref } from 'vue'
import Card from '@/components/Card/index.vue'
type MenuType = {
label: String
callback: () => void
}
const menuRef = ref<MenuType[]>()
const data = ref<number[]>([1, 2, 3, 4, 5, 6])
const status = ref<Boolean>(false)
const pX = ref<Number>(0)
const pY = ref<Number>(0)
const rightMenu = (event: any, id: number) => {
const bodyWidth = document.body.clientWidth
let mouseWidth = event.clientX
if (bodyWidth - 200 < mouseWidth) { //处理边界问题,右键不会移到窗口外面
mouseWidth -= mouseWidth + 200 - bodyWidth
}
event.preventDefault()
pX.value = mouseWidth
pY.value = event.clientY
status.value = true
let menu = [
{
label: '删除',
callback: () => {
data.value = data.value.filter((item: number) => item !== id)
},
},
]
menuRef.value = menu
}
window.addEventListener('click', () => {
status.value = false
})
Card组件
<template>
<nav
class="page"
ref="menuRef"
:style="{ display: !status ? 'none' : '', left: pX + 'px', top: pY + 'px' }"
>
<li v-for="item in list" @click="item.callback()">
{{ item.label }}
</li>
</nav>
</template>
<script lang="ts">
import { defineComponent, PropType, watch, ref } from 'vue'
type MenuType = {
label: String
callback: () => void
}
export default defineComponent({
name: 'Card',
props: {
pX: {
type: Number,
default: 0,
},
pY: {
type: Number,
default: 0,
},
status: {
type: Boolean,
default: false,
},
list: {
type: Array as PropType<MenuType[]>,
},
},
emits: [],
setup(props, { emit }) {
const menuRef = ref<HTMLElement>()
const body = document.querySelector('body')
watch(
() => props.status,
(val) => {
if (val && menuRef.value) {
body?.appendChild(menuRef.value)
} else if (menuRef.value) {
body?.removeChild(menuRef.value)
}
}
)
return {}
},
})
</script>
内容复制
- read : 读取剪切板的内容;
- readText: 读取剪切板文字内容;
- write: 向剪切板中写入文字内容;
- writeText: 向剪切板中写入内容;
<div class="copy" ref="copyRef">测试文字复制</div>
const copyRef = ref<HTMLDivElement>()
1--类似我们选中复制吧,会给文字添加一个背景,跟个智障一样
function copyHandle() {
if (!copyRef.value) return
const range = document.createRange()
range.selectNode(copyRef.value)
const selection = window.getSelection()
if (selection && selection.rangeCount > 0) selection?.removeAllRanges()
selection?.addRange(range)
const result = document.execCommand('copy')
console.log(result)
}
2--Clipboard
不是Clipboard通过实例化创建对象,而是通过Navigator.clipboard全局访问系统剪贴板。
使用 clipboard 的 writeText 方法实现复制
const value = copyRef.value.innerText
const clipboardObj = navigator.clipboard
await clipboardObj.writeText(value)
使用 clipboard 的 write 方法实现复制
async function copyHandle() {
if (!copyRef.value) return
const value = copyRef.value.innerText
const clipboardObj = navigator.clipboard
const type = 'text/plain'
const blob = new Blob([value], { type })
const data = [new ClipboardItem({ [type]: blob })]
await clipboardObj.write(data)
}
验证码
<template>
<div class="s-canvas">
<canvas
ref="canvasRef"
class="canvas"
@click="makeCode"
:width="contentWidth"
:height="contentHeight"
></canvas>
</div>
</template>
<script lang="ts">
import { toRefs, onMounted, watch, defineComponent, ref, nextTick } from 'vue'
import { random } from 'lodash'
export default defineComponent({
name: 'imageCode',
props: {
change: {
// 刷新验证码使用
type: Boolean,
default: false,
},
contentWidth: {
// 验证码图片宽
type: Number,
default: 112,
},
contentHeight: {
// 验证码图片高
type: Number,
default: 38,
},
},
emits: ['getCode'], // 返回验证码加密正确值的函数
setup(props, { emit }) {
const canvasRef = ref<HTMLCanvasElement>()
// 默认值
const defaultData = {
identifyCode: '', // 验证码值,未加密的
identifyCodes: '1234567890', // 生成验证码的元素,可以加入字母
fontSizeMin: 20, // 图片上验证文字的最小值
fontSizeMax: 40, // 图片上验证文字的最小值
backgroundColorMin: 180, // 图片背景色值最小
backgroundColorMax: 240, // 图片背景色值最大
colorMin: 50, // 文字色值最小
colorMax: 160, // 文字色值最大
lineColorMin: 40, // 干扰线色值最小
lineColorMax: 120, // 干扰线色值最大
dotColorMin: 0, // 干扰点色值最小
dotColorMax: 255, // 干扰点色值最大
lineSum: 4, // 干扰线数量
dotSum: 40, // 干扰点数量
}
// 父级传递
const { contentWidth, contentHeight, change } = toRefs(props)
// 生成一个随机的颜色
const randomColor = (min: number, max: number) => {
let r = random(min, max)
let g = random(min, max)
let b = random(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
}
// 创建图形
const drawPic = () => {
// let canvas = document.getElementById('s-canvas')
nextTick(() => {
if (!canvasRef.value) return
let ctx = canvasRef.value.getContext('2d')
if (!ctx) return
ctx.textBaseline = 'bottom'
// 绘制背景
ctx.fillStyle = randomColor(
defaultData.backgroundColorMin,
defaultData.backgroundColorMax
)
ctx.fillRect(0, 0, contentWidth.value, contentHeight.value)
// 绘制文字
for (let i = 0; i < defaultData.identifyCode.length; i++) {
drawText(ctx, defaultData.identifyCode[i], i)
}
drawLine(ctx)
drawDot(ctx)
})
}
// 绘制文字
const drawText = (
ctx: CanvasRenderingContext2D,
txt: string,
i: number
) => {
ctx.fillStyle = randomColor(defaultData.colorMin, defaultData.colorMax)
ctx.font =
random(defaultData.fontSizeMin, defaultData.fontSizeMax) + 'px SimHei'
let x =
(i + 1) * (contentWidth.value / (defaultData.identifyCode.length + 1))
let y = random(defaultData.fontSizeMax, contentHeight.value)
var deg = random(-30, 30)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate((deg * Math.PI) / 180)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate((-deg * Math.PI) / 180)
ctx.translate(-x, -y)
}
// 绘制干扰线
const drawLine = (ctx: CanvasRenderingContext2D) => {
for (let i = 0; i < 4; i++) {
ctx.strokeStyle = randomColor(
defaultData.lineColorMin,
defaultData.lineColorMax
)
ctx.beginPath()
ctx.moveTo(
random(0, contentWidth.value),
random(0, contentHeight.value)
)
ctx.lineTo(
random(0, contentWidth.value),
random(0, contentHeight.value)
)
ctx.stroke()
}
}
// 绘制干扰点
const drawDot = (ctx: CanvasRenderingContext2D) => {
for (let i = 0; i < 60; i++) {
ctx.fillStyle = randomColor(0, 255)
ctx.beginPath()
ctx.arc(
random(0, contentWidth.value),
random(0, contentHeight.value),
1,
0,
2 * Math.PI
)
ctx.fill()
}
}
// 生成图片
const makeCode = () => {
defaultData.identifyCode = ''
for (let i = 0; i < 4; i++) {
defaultData.identifyCode +=
defaultData.identifyCodes[
random(0, defaultData.identifyCodes.length - 1)
]
}
// 绘制图片
drawPic()
// 返回加密后的图片验证码值
emit('getCode', defaultData.identifyCode)
}
// 初识函数,生成图片
onMounted(() => {
makeCode()
})
// 监听change变化,重新生成图片
watch(change, () => {
makeCode()
})
return {
makeCode,
canvasRef,
}
},
})
</script>
<style lang="scss" scoped>
.canvas {
cursor: pointer;
}
</style>