整理文章后提交
This commit is contained in:
1 parent
441dd0e18e
commit
473a07eba4
105 files changed
+1053
-678
No files matched your search
@@ -0,0 +1,73 @@
|
||||
---
|
||||
date: '2022-06-27T19:33:58+08:00'
|
||||
draft: false
|
||||
title: '如何在Vue3的Store中使用i18n'
|
||||
keywords: [ 'vue','vue3','i18n' ]
|
||||
tags: [ 'vue3','i18n' ]
|
||||
categories: [ 'skill' ]
|
||||
---
|
||||
|
||||
## 使用环境
|
||||
|
||||
> `Vue`的版本为:`3.2.36`,
|
||||
>
|
||||
> `vue-router`的版本为:`4.0.16`
|
||||
>
|
||||
> `vue-i18n`的版本为:`9.2.0-beta.40`
|
||||
|
||||
几乎都最新版本了
|
||||
|
||||

|
||||
|
||||
## 问题复现
|
||||
|
||||
使用的`element-plus`框架进行项目的搭建,在登陆的时候在全局路由中进行密码的校验,如果密码错误或正确使用`element-plus`中的提示组件登录的提示,但是提示的内容要根据选择的语言进行分别的提示
|
||||
|
||||
这个似乎很正常的需求,但是因为使用的`vue3`中的`setup`,并且在路由中是使用的`ts`,所以不能使用this,并且像`vue`文件中使用的引入方式:
|
||||
```js
|
||||
const { t, d, n, locale } = useI18n()
|
||||
```
|
||||
|
||||
这种方式也是不行的,因为执行顺序的前后问题,在路由加载时`useI18n()`还没有引入执行,所以这种方式的引入会直接报错的
|
||||
|
||||
## 问题解决
|
||||
|
||||
因为在`.vue`文件中会使用对应的方法将对应的内容引入,但是当执行路由时这个内容并没有加载,但是这个代码一定是存在并且可以直接运行的,所以可以通过其他方式直接手动将对应需要的代码引入,而不使用提供的方法
|
||||
|
||||
当在创建对应的i18n时,会先将对应的内容进行创建和导出:
|
||||
|
||||

|
||||
|
||||
|
||||
在这个文件中创建了i18n,并且对特定的配置项进行了指定,但是导出的这个i18n中有什么?
|
||||
|
||||

|
||||
|
||||
|
||||
在配置的文件中已经存在了要使用的方法,也就是导出的:`t`,`d`,`n`等,要使用的方法也在这里面
|
||||
|
||||

|
||||
|
||||
|
||||
在这个`global`中存在了对应的全局的方法,不需要通过i18n指定的方法进行引入执行,可以直接使用,所以这个就是要手动引入的内容
|
||||
|
||||
## 解决
|
||||
|
||||

|
||||
|
||||
|
||||
使用这种方法问题得到解决,不过在尝试过程中,这种两种方式使用的i18n也是有区别的
|
||||
|
||||
在引入的过程中,因为方式不同,所以引入的方法其实也不是同一个
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
不过在对应的注释中也能略微看出二者的区别
|
||||
|
||||

|
||||
|
||||
|
||||
使用方法引入的‘t’应当也有特有的内容,这里只进行列举,不继续深入探讨。
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
---
|
||||
date: '2022-08-26T12:33:58+08:00'
|
||||
draft: false
|
||||
title: 'JavaScript和Vue中实现表格(table)固定表头和首列【提供Vue和原生代码】'
|
||||
keywords: [ 'vue','vue3','JavaScript' ]
|
||||
tags: [ 'vue3','JavaScript' ]
|
||||
categories: [ 'skill' ]
|
||||
---
|
||||
|
||||
## 写在前面
|
||||
|
||||
本文主要介绍关于`JS`或`Vue`中如何进行表头,列固定,可以根据实际应用场景应用于`原生`,`Vue`,`移动端`,`小程序`中
|
||||
|
||||
实际效果展示:
|
||||
|
||||

|
||||
|
||||
对于列的固定,`table`中有对应的方法,但是如果列和表头都要固定,只能通过其他方式实现,<span style="color:red;">如果您找到了更好的自身方法,还请斧正</span>
|
||||
|
||||
## 思路概述
|
||||
|
||||
`表头,列头,表格本身,这三个内容被分为了三块元素,将这三个内容进行抽离,并且通过定位和大盒子的包裹进行样式管理。`
|
||||
|
||||
【当要进行滚动时,只要对滚动事件进行绑定,让`表头和列头显示对应的内容就完成了滚动的操作`】
|
||||
|
||||
下面有`Vue`组件的和`JavaScript`原生的代码,可以直接运行查看逻辑和效果
|
||||
|
||||
## 具体实现
|
||||
|
||||
整体代码,`可以直接创建组件,将代码复制到组件中使用`,在`App`中引用运行【基于`vue3+ts+less`实现,其他版本会在后面给出修改思路】`【最下面也提供了原生写法】`
|
||||
|
||||
```html
|
||||
<!--
|
||||
~ Time:2022/8/9 13:06 29
|
||||
~ Name:fixmeTable.vue
|
||||
~ Path:src/components/table
|
||||
~ ProjectName:element-plus
|
||||
~ Author:charlatan
|
||||
~
|
||||
~ Il n'ya qu'un héroïsme au monde :
|
||||
~ c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
-->
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const row = 20
|
||||
const column = 30
|
||||
|
||||
let top = ref('0px')
|
||||
let left = ref('0px')
|
||||
const Scroll = (event: Event) => {
|
||||
top.value = -event.target.scrollTop + 'px'
|
||||
left.value = -event.target.scrollLeft + 'px'
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<h3>
|
||||
列头表头固定table
|
||||
</h3>
|
||||
<hr>
|
||||
<!-- 表格-->
|
||||
<div class="table">
|
||||
<!-- 表头-->
|
||||
<div class="rowHeader">
|
||||
<table class="rowHeader-table">
|
||||
<tr>
|
||||
<td class="td" v-for="(item,index) in row" :key="index">
|
||||
{{ item }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 列头-->
|
||||
<div class="columnHeader">
|
||||
<table class="columnHeader-table">
|
||||
<tr v-for="(RootItem,index) in column" :key="index">
|
||||
<td class="td">
|
||||
{{ String.fromCharCode(RootItem + 64) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 表格-->
|
||||
<div class="tableBody" @scroll="Scroll($event)">
|
||||
<table class="tableBody-table">
|
||||
<tr v-for="(RootItem,index) in column" :key="index">
|
||||
<td
|
||||
class="td" v-for="(item,index) in row" :key="index">
|
||||
{{ item + String.fromCharCode(RootItem + 64) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="less">
|
||||
.table {
|
||||
border: 1px solid red;
|
||||
padding: 1rem;
|
||||
border-radius: 1rem;
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
|
||||
// 表头
|
||||
.rowHeader {
|
||||
position: relative;
|
||||
width: 260px;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
left: 30px;
|
||||
|
||||
.rowHeader-table {
|
||||
position: relative;
|
||||
left: v-bind(left);
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
// 列头
|
||||
.columnHeader {
|
||||
position: relative;
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
top: 3px;
|
||||
|
||||
.columnHeader-table {
|
||||
position: relative;
|
||||
top: v-bind(top)
|
||||
}
|
||||
}
|
||||
|
||||
// 表格本体
|
||||
.tableBody {
|
||||
width: 265px;
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
left: 50px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 表格元素
|
||||
tr {
|
||||
width: fit-content;
|
||||
white-space: normal;
|
||||
display: flex;
|
||||
|
||||
.td {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
|
||||
|
||||
1. `html`部分:主要进行框架的设计,这里表头,列头,表格本体分为三份
|
||||
|
||||
```html
|
||||
<template>
|
||||
<h3>
|
||||
列头表头固定table
|
||||
</h3>
|
||||
<hr>
|
||||
<!-- 表格-->
|
||||
<div class="table">
|
||||
|
||||
<!-- 表头-->
|
||||
<div class="rowHeader">
|
||||
<table class="rowHeader-table">
|
||||
<tr>
|
||||
<td class="td" v-for="(item,index) in row" :key="index">
|
||||
{{ item }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 列头-->
|
||||
<div class="columnHeader">
|
||||
<table class="columnHeader-table">
|
||||
<tr v-for="(RootItem,index) in column" :key="index">
|
||||
<td class="td">
|
||||
{{ String.fromCharCode(RootItem + 64) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 表格-->
|
||||
<div class="tableBody" @scroll="Scroll($event)">
|
||||
<table class="tableBody-table">
|
||||
<tr v-for="(RootItem,index) in column" :key="index">
|
||||
<td
|
||||
class="td" v-for="(item,index) in row" :key="index">
|
||||
{{ item + String.fromCharCode(RootItem + 64) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
||||
|
||||
内容分为了三部分,这三部分将相互独立,通过样式的调节将三部分内容进行统一的管理。
|
||||
|
||||
这里使用的是`table`进行了内容的填充,因为表头和列头是单独的元素,所以可以使用其他内容如`div`等,通过样式上的和交互上的进行协调统一,这里不在赘述
|
||||
|
||||
2. 样式上的内容,因为主要是功能,这里样式使用`less`进行简单绘制
|
||||
|
||||
```css
|
||||
<style scoped lang="less">
|
||||
.table {
|
||||
border: 1px solid red;
|
||||
padding: 1rem;
|
||||
border-radius: 1rem;
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
|
||||
// 表头
|
||||
.rowHeader {
|
||||
position: relative;
|
||||
width: 260px;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
left: 30px;
|
||||
|
||||
.rowHeader-table {
|
||||
position: relative;
|
||||
left: v-bind(left);
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
// 列头
|
||||
.columnHeader {
|
||||
position: relative;
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
top: 3px;
|
||||
|
||||
.columnHeader-table {
|
||||
position: relative;
|
||||
top: v-bind(top)
|
||||
}
|
||||
}
|
||||
|
||||
// 表格本体
|
||||
.tableBody {
|
||||
width: 265px;
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
left: 50px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 表格元素
|
||||
tr {
|
||||
width: fit-content;
|
||||
white-space: normal;
|
||||
display: flex;
|
||||
|
||||
.td {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
内容上和定义的结构进行统一调节,这里需要主要的是:<span style='color:red;font-weight:900;'>因为表格的宽度和表头的宽度对应,表格的高度和列头的高度固定,所以建议在定义时考虑好对应的宽高对应关系,方便调节</span>
|
||||
|
||||
在定义好表头和列头时,对与展示的部分通过外部的`div`进行定位的调节进行展示,内部的表格部分通过宽度的固定来达到样式统一,使用相对定位来完成展示内容的切换
|
||||
|
||||
内部使用了Vue3提供的`v-bind`,如果你使用的时vue2或其他内容请更换为内联样式或其他方式
|
||||
|
||||
`v-bind`为Vue3中提供,主要是将绑定的内容转换为自定义标签使用,具体介绍可以看我的另一篇文章:[Vue3新属性 — v-bind in css](https://blog.csdn.net/weixin_52235488/article/details/126290046?spm=1001.2014.3001.5502),里面有用法和原理的详细介绍
|
||||
|
||||
3. 逻辑部分:主要为内部的真正的表格绑定了滚动的监听,
|
||||
|
||||
```html
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 定义行和列
|
||||
const row = 20
|
||||
const column = 30
|
||||
|
||||
// 将内容进行响应式定义
|
||||
let top = ref('0px')
|
||||
let left = ref('0px')
|
||||
|
||||
// 绑定对应的监听事件
|
||||
const Scroll = (event: Event) => {
|
||||
top.value = -event.target.scrollTop + 'px'
|
||||
left.value = -event.target.scrollLeft + 'px'
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
这里使用的动态数据在`v-bind`中进行,这里直接修改即可
|
||||
|
||||
## 其他环境中要修改的内容
|
||||
|
||||
这里对常见问题进行解决,如果没有匹配,请评论或找其他方式解决
|
||||
|
||||
1. `原生JavaScript中使用`:如果你完全没有使用过`Vue`,上面的代码我也改成了原生的版本,逻辑一样,这里就只放代码不做介绍了`直接创建文件复制使用`
|
||||
|
||||
```html
|
||||
<!--
|
||||
~ Time:2022/8/12 9:02 36
|
||||
~ Name:test1.html
|
||||
~ Path:
|
||||
~ ProjectName:element-plus
|
||||
~ Author:charlatan
|
||||
~
|
||||
~ Il n'ya qu'un héroïsme au monde :
|
||||
~ c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=edge" http-equiv="X-UA-Compatible">
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<title>Title</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font: 500 15px YouYuan;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*-------以上为默认设置(The above is the default setting)--------*/
|
||||
|
||||
|
||||
.table {
|
||||
border: 1px solid red;
|
||||
padding: 1rem;
|
||||
border-radius: 1rem;
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.rowHeader {
|
||||
position: relative;
|
||||
width: 260px;
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
left: 30px;
|
||||
}
|
||||
|
||||
.rowHeader-table {
|
||||
position: relative;
|
||||
left: 0;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.columnHeader {
|
||||
position: relative;
|
||||
max-height: 270px;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.columnHeader-table {
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.tableBody {
|
||||
width: 265px;
|
||||
height: 270px;
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
left: 50px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
tr {
|
||||
width: fit-content;
|
||||
white-space: normal;
|
||||
display: flex;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.td {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="table">
|
||||
<!-- 表头-->
|
||||
<div class="rowHeader">
|
||||
<table class="rowHeader-table">
|
||||
<tr id="rowHeader-table-tr"></tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 列头-->
|
||||
<div class="columnHeader">
|
||||
<table class="columnHeader-table" id="columnHeader-table-tr"></table>
|
||||
</div>
|
||||
<!-- 表格-->
|
||||
<div class="tableBody" id="scroll">
|
||||
<table class="tableBody-table" id="tableBody-table-tr"></table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
// 定义行和列
|
||||
const row = 30
|
||||
const column = 30
|
||||
|
||||
// 获取表头
|
||||
let rowHeard = document.getElementById('rowHeader-table-tr')
|
||||
// 创建表头元素
|
||||
for (let i = 0, len = row; i < len; i++) {
|
||||
// 获取元素
|
||||
let td = document.createElement('td')
|
||||
// 添加样式
|
||||
td.classList.add('td')
|
||||
// 添加内容
|
||||
let testNode = document.createTextNode(i)
|
||||
td.appendChild(testNode)
|
||||
// 将表头放置到指定位置
|
||||
rowHeard.appendChild(td)
|
||||
}
|
||||
|
||||
// 创建表头元素
|
||||
let columnHeard = document.getElementById('columnHeader-table-tr')
|
||||
// 创建元素
|
||||
for (let i = 0, len = column; i < len; i++) {
|
||||
let tr = document.createElement('tr')
|
||||
let td = document.createElement('td')
|
||||
td.classList.add('td')
|
||||
td.appendChild(document.createTextNode(String.fromCharCode(i + 64)))
|
||||
tr.appendChild(td)
|
||||
columnHeard.appendChild(tr)
|
||||
}
|
||||
|
||||
// 创建表格元素
|
||||
let table = document.getElementById('tableBody-table-tr')
|
||||
for (let i = 0, len = column; i < len; i++) {
|
||||
let tr = document.createElement('tr')
|
||||
for (let j = 0, len = row; j < len; j++) {
|
||||
let td = document.createElement('td')
|
||||
td.classList.add('td')
|
||||
td.appendChild(document.createTextNode(i + String.fromCharCode(j + 64)))
|
||||
tr.appendChild(td)
|
||||
}
|
||||
table.appendChild(tr)
|
||||
}
|
||||
|
||||
// 获取表头和列头滚动元素
|
||||
let row_heard = document.getElementsByClassName('rowHeader-table')[0]
|
||||
let column_heard = document.getElementsByClassName('columnHeader-table')[0]
|
||||
|
||||
// 绑定滚动时间
|
||||
let scroll = document.getElementById('scroll')
|
||||
scroll.onscroll = function (event) {
|
||||
row_heard.style.left = -event.target.scrollLeft + 'px'
|
||||
column_heard.style.top = -event.target.scrollTop + 'px'
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
```
|
||||
|
||||
主要通过的是JS的元素创建然后将元素添加至对应的内容中,然后进行事件的绑定,从而完成整体逻辑
|
||||
|
||||
2. `React`和`小程序中`,二者都是可以进行数据的绑定,元素的循环处理更加方法,小程序中没有鼠标,可能要更换为手指滑动操作,对于这个逻辑相同,`绑定元素的移动距离`,从而让表头和列头跟随移动从而达到同步的效果和目的
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
date: '2022-08-25T10:33:58+08:00'
|
||||
draft: false
|
||||
title: 'Vue3中的ref为何要用.value进行值的调用?'
|
||||
keywords: [ 'vue','vue3' ]
|
||||
tags: [ 'vue3' ]
|
||||
categories: [ 'skill' ]
|
||||
---
|
||||
|
||||
在`Vue2`中,所有的数据都通过一个Data进行统一的返回,并且在data中对某个组件要用的数据进行统一的管理,常见的使用形式是这样的:
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div class="div">
|
||||
<todos :Obj="tos" :removeObj="removeObj"></todos>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import search from '@/components/search'
|
||||
import todos from '@/components/todos'
|
||||
import all from '@/components/all'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
data () {
|
||||
return {
|
||||
tos: [
|
||||
{ id: '001', value: '第一个', done: true },
|
||||
{ id: '002', value: '第二个', done: true },
|
||||
{ id: '003', value: '第三个', done: false },
|
||||
{ id: '004', value: '第四个', done: true },
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: { },
|
||||
components: {
|
||||
search, todos, all,
|
||||
},
|
||||
methods: {
|
||||
removeObj (obj) {
|
||||
console.log(obj.id)
|
||||
this.tos = this.tos.filter(item => item.id !== obj.id)
|
||||
console.log(this.tos)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
// 样式
|
||||
</style>
|
||||
```
|
||||
|
||||
可以看出来这里定义的内容都在一个数组中进行,或者是一个函数,将要使用的数据返回出来,这里无论怎么进行操作处理,最终进行数据代理的时候得到的都是一个对象,Vue2中直接通过`defineProperty`进行处理,并绑定对应的监听事件进行响应式的处理。
|
||||
|
||||
而Vue3中,数据的定义可以是单独的,Vue可以让我们随时需要随时定义,这也就带来了另一个问题,我需要的一个数据可能不是对象
|
||||
|
||||
```js
|
||||
<script lang="ts" setup>
|
||||
|
||||
let str = ref('响应式字符串')
|
||||
let obj = reactive({
|
||||
name: '张三',
|
||||
age: 10,
|
||||
})
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
如果要定义的数据不是对象,还需要代理会怎么样?
|
||||
|
||||
在Vue2中数据的定义都在对象中统一进行,也就不会出现这种情况,如果一定要代理一个单独的数据呢?
|
||||
|
||||
Vue2中的数据代理通过`defineProperty`进行实现,也就是说我们要让`defineProperty`代理一个普通的数据,而不是一个对象,在`defineProperty`的MDN的文档中是这样定义的:
|
||||
|
||||
> **`Object.defineProperty()`** 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
|
||||
|
||||
通过这个可以明确看出,只能进行对象的代理,不能进行普通数据的代理,如果使用普通数据类型会直接报以下错误[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1Lm0OSJ-1661407967498)(Vue3中的ref为何要用.value进行值的调用?.assets/image-20220825094409254.png)]
|
||||
|
||||
在Vue3中数据代理可以使用单一数据了,并且也改进了数据代理的方式,使用的是`Peoxy`完成了数据代理,而MDN中对`Proxy`也进行了定义:
|
||||
|
||||
> **Proxy** 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
|
||||
|
||||
可以看出,`Proxy`依然是为对象服务,而不是普通的内容,这样问题似乎就解决了
|
||||
|
||||
本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
|
||||
|
||||
可以看出,`Proxy`依然是为对象服务,而不是普通的内容,这样问题似乎就解决了
|
||||
|
||||
> 即使是Vue3中使用的`Proxy`的代理方式也不能进行普通数据的代理,所以当调用`Ref`的时候其实仍然创建了一个`Proxy`对象,并且Vue帮你给这个对象了一个`value`属性,属性值就是你定义的内容,改变的时候监视的改变依然是通过`Proxy`的数据劫持来进行响应式的处理,而模板中使用的时候`Vue`会默认调用对应的`value`属性,从而完成模板中的内容的直接调用
|
||||
@@ -0,0 +1,377 @@
|
||||
---
|
||||
date: '2022-08-11T16:44:29+08:00'
|
||||
draft: false
|
||||
title: 'Vue3新属性 — css中使用v-bind(v-bind in css)'
|
||||
keywords: [ 'vue','vue3' ]
|
||||
tags: [ 'vue3' ]
|
||||
categories: [ 'skill' ]
|
||||
---
|
||||
|
||||
# Vue3新属性:CSS 中的 `v-bind()`
|
||||
|
||||
## 写在前面:
|
||||
|
||||
本文主要介绍Vue3中的新增的`v-bind()`的常用使用方式,主要包括在`css`,`less`,`scss`中的使用,可以参考官方文档查看:[Vue3官方文档](https://cn.vuejs.org/api/sfc-css-features.html#v-bind-in-css),本文将主要通过一个demo中的使用来展示
|
||||
|
||||
## 实际使用:
|
||||
|
||||
先创建一个通过的页面结构,因为是结构是通用内容,所以这里在直接进行简单的定义
|
||||
|
||||
```html
|
||||
<div class="div">
|
||||
<div class="span">
|
||||
<div class="span_title">
|
||||
这是测试文字
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
- 在`css`中:
|
||||
|
||||
在`css`中主要通过直接进行绑定,主要包括几种使用方式(我自己编的名词):`直接使用`、`拼接使用`、`对象调用`、`组合使用`【这是我想到的几种常见方式,如果有特殊需求,可以评论区沟通】
|
||||
|
||||
在JS中先对需要用的数据进行定义:
|
||||
|
||||
```js
|
||||
|
||||
// 进行拼接调用测试的数据
|
||||
let width = 400
|
||||
|
||||
// 直接调用的数据
|
||||
let div_height = '400px'
|
||||
let div_color = '#e89393'
|
||||
|
||||
// 对象调用的数据
|
||||
let span = {
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
color: 'green',
|
||||
}
|
||||
|
||||
// 组合调用的数据
|
||||
let transition = 'cubic-bezier(0, 1.5, .6, 1)'
|
||||
```
|
||||
|
||||
然后这些数据直接在`css`中进行使用,使用`v-bind()`进行绑定
|
||||
|
||||
```css
|
||||
<style scoped lang="css">
|
||||
.div {
|
||||
/* 拼接使用 */
|
||||
width: v-bind(width + 'px');
|
||||
/* 直接使用 */
|
||||
height: v-bind(div_height);
|
||||
background: v-bind(div_color);
|
||||
}
|
||||
|
||||
.span {
|
||||
/* 对象调用 */
|
||||
width: v-bind('span.width');
|
||||
height: v-bind('span.height');
|
||||
background: v-bind('span.color');
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.span_title {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: #000;
|
||||
color: white;
|
||||
/* 组合使用 */
|
||||
transition: all .9s v-bind(transition);
|
||||
}
|
||||
|
||||
.span:hover .span_title {
|
||||
border-radius: 50%;
|
||||
background: #a5f5b8;
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
在对应的四个方式的调用中:
|
||||
|
||||
`直接使用`:完全没有问题
|
||||
|
||||
`拼接使用`:这个在`css`中没有问题,不过在`scss`中会出现错误,这个在下面的`scss`中会有详细介绍
|
||||
|
||||
`对象调用`:对象的调用和直接使用类似,不过不同的是,需要使用引号的包裹才能正常使用,如果直接书写会报错
|
||||
|
||||
`组合使用`:完全没问题
|
||||
|
||||
- 在`less`中:
|
||||
|
||||
使用的数据同样是上面给出的数据,这里直接改样式的内容了
|
||||
|
||||
```css
|
||||
<style scoped lang="less">
|
||||
// 使用变量承接
|
||||
@height: v-bind(div_height);
|
||||
|
||||
.div {
|
||||
width: 400px;
|
||||
/* 直接使用 */
|
||||
height: @height;
|
||||
background: v-bind(div_color);
|
||||
|
||||
.span {
|
||||
@width: v-bind('span.width');
|
||||
|
||||
/* 对象调用 */
|
||||
width: @width;
|
||||
height: v-bind('span.height');
|
||||
background: v-bind('span.color');
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.span_title {
|
||||
@transition: v-bind(transition);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: #000;
|
||||
color: white;
|
||||
/* 组合使用 */
|
||||
transition: all .9s @transition;
|
||||
}
|
||||
|
||||
&:hover .span_title {
|
||||
border-radius: 50%;
|
||||
background: #a5f5b8;
|
||||
color: #ff0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
`直接使用`:没有问题
|
||||
|
||||
`拼接使用`:**存在问题**,在下面尝试进行了解决
|
||||
|
||||
`对象调用`:没问题
|
||||
|
||||
`组合使用`:没问题
|
||||
|
||||
<h3>问题:</h3>
|
||||
|
||||
> 在拼接使用有几种方式:
|
||||
>
|
||||
> ```js
|
||||
> // 定义使用的数据
|
||||
> let width = 400
|
||||
> ```
|
||||
>
|
||||
> ```css
|
||||
> // 直接拼接
|
||||
> @width: v-bind( width + 'px');
|
||||
> width: @width;
|
||||
>
|
||||
> // 拿到内容后拼接
|
||||
> @width: v-bind(width) + 'px';
|
||||
> width: @width;
|
||||
>
|
||||
> // 使用时拼接
|
||||
> @width: v-bind(width);
|
||||
> width: @width + 'px';
|
||||
>
|
||||
> ```
|
||||
>
|
||||
> 常用的拼接方法一般为这几种(如果有欠缺还请补充),这几种方式都进行了尝试,其中第二种第三种会没有效果,第一种会直接报错
|
||||
|
||||
|
||||
|
||||
<h3>问题分析(尝试解决):【这部分会很长,如果不想看,可以直接跳到解决方法】</h3>
|
||||
|
||||
首先是第一种,如果使用的话会直接报错,报错内容为:
|
||||
|
||||

|
||||
|
||||
因为`less`的直接报错,导致定义的变量压根就没有被编译出来,从而报错
|
||||
|
||||
第二种和第三种错误一样:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在这种使用方式中,变量可以正确承接,但是不能完成拼接的操作,导致只有变量而没有单位,并且可以看出最终都被翻译为`var(--变量名)`来执行,所以顺便也对`var()`进行了拼接测试
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
这里进行调用内容的定义,并且模仿编译后的内容,进行使用,在这种情况下尝试使用拼接
|
||||
|
||||
> 尝试的拼接方式:
|
||||
>
|
||||
> `直接拼接`:
|
||||
>
|
||||
> ```css
|
||||
> :root{
|
||||
> --test:400 + 'px';
|
||||
> }
|
||||
> /* 使用 */
|
||||
> width: var(--test);
|
||||
> ```
|
||||
>
|
||||
> `接受变量后拼接`:
|
||||
>
|
||||
> ```css
|
||||
> :root{
|
||||
> --test:400 + 'px';
|
||||
> }
|
||||
> /* 使用 */
|
||||
> width: var(--test+ 'px');
|
||||
> ```
|
||||
>
|
||||
> `继承后拼接`:
|
||||
>
|
||||
> ```css
|
||||
> :root{
|
||||
> --test:400 + 'px';
|
||||
> }
|
||||
> /* 使用 */
|
||||
> width: var(--test) + 'px';
|
||||
> ```
|
||||
|
||||
结果也非常让不出意外的都不行,并且在第二种方式也是直接报错的,在寻找问题的过程中,发现了更加`amazing`的事情:
|
||||
|
||||

|
||||
|
||||
|
||||
这个变量压根就没定义,或者说没被识别到,所以重新模仿`Vue`直接定义行内样式,并且使用拼接尝试:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
这种直接的拼接方式直接将所有内容都进行了拼接,再换一种思路:使用`V-bind`这个V-bind指的是数据的而不是样式:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
这次问题得到了解决,并且样式数据也是响应式的单个数据,并且也是在`less`中正确使用,应该也算解决问题吧
|
||||
|
||||
<h3>解决方式(思路):</h3>
|
||||
|
||||
将变量的内容在`行内样式`使用拼接的方式进行定义,然后在定义的`less或scss`中进行使用,因为定义的样式是行内样式,所以优先级和变量出现的位置,都是在使用之前,所以可以正常使用
|
||||
|
||||
<h3>完整代码:</h3>
|
||||
|
||||
> 使用数据的定义:
|
||||
>
|
||||
> ```js
|
||||
> // 大部分数据和预先提供的数据一样(这里只写了新增数据)
|
||||
> let test = 400
|
||||
> ```
|
||||
>
|
||||
> 页面结构:
|
||||
>
|
||||
> ```html
|
||||
> <!-- 改变的内容为下面这行(其他内容和原来内容保持一致)-->
|
||||
> <!-- 【在这里对要使用的数据进行单位的绑定】-->
|
||||
> <div class="div" :style="{'--test' :test + 'px'}">
|
||||
> <div class="span">
|
||||
> <div class="span_title">
|
||||
> 这是测试文字
|
||||
> </div>
|
||||
> </div>
|
||||
> </div>
|
||||
> ```
|
||||
>
|
||||
> 样式的使用:
|
||||
>
|
||||
> ```css
|
||||
> <style scoped lang="less">
|
||||
> // 承接使用
|
||||
> @width: var(--test);
|
||||
>
|
||||
> .div {
|
||||
> /* 使用 */
|
||||
> width: @width;
|
||||
> /* 或者直接使用 */
|
||||
> width: var(--test);
|
||||
> height: 400px;
|
||||
> background: red;
|
||||
> }
|
||||
> </style>
|
||||
> ```
|
||||
>
|
||||
|
||||
|
||||
|
||||
在`css`的测试中几种方式也都能完美运行,并且在`less`的特有的数据绑定中也都没有问题,对于`拼接使用`是可以正常使用的。
|
||||
|
||||
我用的工具是`webstorm`less也是唯一一个没有报错的提示的(工具内的报错提示,可能不认识新内容把)
|
||||
|
||||
- 在`scss`中:
|
||||
|
||||
```css
|
||||
<style scoped lang="scss">
|
||||
// 使用变量承接
|
||||
$width: v-bind(width + 'px');
|
||||
$height: v-bind(div_height);
|
||||
|
||||
.div {
|
||||
/* 拼接使用 */
|
||||
width: $width;
|
||||
/* 直接使用 */
|
||||
height: $height;
|
||||
background: v-bind(div_color);
|
||||
|
||||
.span {
|
||||
$width: v-bind('span.width');
|
||||
|
||||
/* 对象调用 */
|
||||
width: $width;
|
||||
height: v-bind('span.height');
|
||||
background: v-bind('span.color');
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.span_title {
|
||||
$transition: v-bind(transition);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: #000;
|
||||
color: white;
|
||||
/* 组合使用 */
|
||||
transition: all .9s $transition;
|
||||
}
|
||||
|
||||
&:hover .span_title {
|
||||
border-radius: 50%;
|
||||
background: #a5f5b8;
|
||||
color: #ff0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
`scss`相对`less`一些方法更加灵活,在`v-bind()`的使用中,拼接使用会出现错误,这个暂时按下不表,在原理中会详细阐述
|
||||
|
||||
- 执行原理:
|
||||
|
||||
`v-bind() in css`并没有进行劫持或者其他操作,他主要完成的任务是将`v-bind()`中的内容通过自定义属性的方式进行了重新定义,在编译后代码中可以看到
|
||||
|
||||

|
||||
|
||||
|
||||
所有的数据直接在自定义属性中进行,并且直接对应引用,自定义属性的内容的改变影响视图的效果,从而达到数据影响视图的效果,这个在使用中`less`,`css`中完全没有问题
|
||||
|
||||
但是,在`scss`中,因为编译之后`名字无法进行匹配`从而造成样式的丢失
|
||||
|
||||

|
||||
|
||||
|
||||
可以看到,使用的名字和编译的名字并不匹配,从而出错,这个使用时需要注意
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
date: '2022-08-09T10:33:58+08:00'
|
||||
draft: false
|
||||
title: '在JavaScript获取Promise的状态'
|
||||
keywords: [ 'JavaScript','Promise' ]
|
||||
tags: [ 'JavaScript' ]
|
||||
categories: [ 'skill' ]
|
||||
---
|
||||
|
||||
# 写在前面
|
||||
|
||||
本文属于对`stackoverflow`中写法的解析,原文链接:[**Stack Overflow** ](https://stackoverflow.com/questions/30564053/how-can-i-synchronously-determine-a-javascript-promises-state)
|
||||
|
||||
如果你在其他环境下遇到同样问题,这个[文章](https://blog.csdn.net/Lee_01/article/details/124892590)可能也会有帮助
|
||||
|
||||
# 问题复现
|
||||
|
||||
如何在代码执行过程中获取到`promise`的状态?
|
||||
|
||||
如果你想寻找或尝试通过原生的属性,或者指定API进行访问,基本可以放弃了,我也是看了很多博客的确没找到,如果您找了其他方式,还望指教
|
||||
|
||||
# 解决方式
|
||||
|
||||
本文中提到的解决方式主要是继续`stackoverflow`中提供的解决方式【完整代码】
|
||||
|
||||
```js
|
||||
/**
|
||||
* 传入需要测试的 Promise 对象,将对应结果返回
|
||||
* @param promise 需要测试的 Promise 对象
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
const promiseState = promise => {
|
||||
const target = {}
|
||||
return Promise.race([promise, target]).then(
|
||||
value => (value === target) ? 'pending' : 'fulfilled',
|
||||
() => 'rejected',
|
||||
)
|
||||
}
|
||||
|
||||
// 测试代码
|
||||
let a = Promise.resolve();
|
||||
let b = Promise.reject();
|
||||
let c = new Promise(() => {});
|
||||
|
||||
promiseState(a).then(state => console.log(state)); // fulfilled
|
||||
promiseState(b).then(state => console.log(state)); // rejected
|
||||
promiseState(c).then(state => console.log(state)); // pending
|
||||
```
|
||||
|
||||
这种方式通过`promise`中的`race()`方法来进行了状态的判断,非常奇妙的一种方式
|
||||
|
||||
# 代码分析
|
||||
|
||||
1. 在方法中会接收一个`promise`对象,开始了整个方法
|
||||
|
||||
2. 进入方法后会先创建一个`target`对象,这个对象只用于后续的匹配,没有其他含义
|
||||
|
||||
```js
|
||||
const target = {}
|
||||
```
|
||||
|
||||
3. 然后开始最核心的部分,因为`stackoverflow`中对代码进行简写,可以先进行代码的还原
|
||||
|
||||
```js
|
||||
return Promise.race([promise, target]).then(
|
||||
// 成功回调
|
||||
value => {
|
||||
return (value === target) ? 'pending' : 'fulfilled'
|
||||
},
|
||||
// 失败回调
|
||||
() => {
|
||||
return 'rejected'
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
可以复现出这种结构,`promise`的`race`开始后,接收两个对象,一个为刚刚创建的`target`对象,还有一个是接收到的`promise`对象,当两个其中一个状态结束时,整个`Promise.race()`结束,这时分为三种情况
|
||||
|
||||
1. 当传入的`promise`为`pending`状态时,`Promise.race`会找到最先有确定状态的元素,并将其返回,因为`promise`没有结束,那么返回值对象会接收到定义的`target`,因为`target`的状态是确定的,这时`value`接收到的值就是已经确定状态的`target`,如果进行对比,那么他们两个一定是相等的,这时也就是返回`pending`
|
||||
2. 当传入的`promise`为`fulfilled`状态时,相当于`promise`已经有确定的值了,`Promise.race`匹配到第一个直接结束,并将匹配到的内容返回,返回的内容因为是一个全新的对象,对象的内存地址不可能相等,所以判断结果是`false`,也就返回`fulfilled`
|
||||
3. 当传入的`promise`为`rejected`状态时,`promise`状态确定,那么因为状态报错,直接进入`catch`中,走失败回调,这个回调一旦执行,就可以判定`promsie`结束,并且内容出现报错,直接返回`rejected`即可
|
||||
4. 在调用的时候,因为返回的时会将对应的状态通过`promise`返回,所以直接通过调用方法之后的`then`中指定回调来完成状态的获取
|
||||
|
||||
- **值得注意的是**:`Promise.race()`在匹配的过程中,一定保证要判断的`promise`在前,因为只有当`promise`状态不确定时才会判断第二个内容的状态,如果将状态已经确定的`target`放在第一个,那么将不会再进行`promise`的判断,返回结果永远为`fulfilled`
|
||||
|
||||
- 并且因为`catch`有两种形式,可以进行变形,这种形式可能更常见(根据个人习惯了)
|
||||
|
||||
```js
|
||||
const promiseState = promise => {
|
||||
const target = {}
|
||||
return Promise.race([promise, target]).then(
|
||||
value => {
|
||||
return (value === target) ? 'pending' : 'fulfilled'
|
||||
},
|
||||
).catch(() => {
|
||||
return 'rejected'
|
||||
})
|
||||
}
|
||||
```
|
||||
Reference in new issue
Block a user