Vue3的技术点
reactive数据回显问题(保持响应式)
- 方法一:使用
ref,把reactive改成ref,如下:
const dataInfo = ref({});
requestApi()
.then((res) => {
let myData = res.data:
dataInfo.value = myData.data;
})
- 方法二: 使用
reactive,外面再包裹一层,如下:
const dataInfo = reactive({
data: {},
nextPage: null
});
requestApi()
.then((res) => {
let myData = res.data:
dataInfo.data = myData.data;
dataInfo.nextPage = myData.nextPage
})
- 方法三: 使用
Object.assign(),如下:
const dataInfo = reactive({
title: "",
name: ""
});
requestApi()
.then((res) => {
let myData = res.data:
// 如果 myData.data 是一个对象
Object.assign(dataInfo, myData.data);
// 如果 myData.data是一个数组
Object.assign(dataInfo, {...myData.data});
})
拓展:
-
表单清空:
- 可以在定义reactive数据的时候再定义一个reset:
const resetForm = reactive({...dataForm}); - 这样清空数据的时候就可以这样使用:
Object.assign(dataForm,resetFrom);
- 可以在定义reactive数据的时候再定义一个reset:
-
为何对象重新赋值后,reactive会丢失响应式,而ref不会。 参考
路由
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
const cardId = route.query.id; //获取路由参数
const goList = () => { //路由跳转
router.push({name: 'card_articleList'});
};
hooks添加公共方法
- 什么是hook?--本质是一个函数,把setup函数中使用的Composition API进行了封装。
- 类似于vue2.x中的mixin。
- 自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂。 参考文献
封装【上拉加载下拉刷新】的方法.
// @/hooks/useFetchListData.js
import { debounce, cloneDeep } from "lodash";
import { reactive, ref, toRef, toRefs, watch } from "vue";
import { toast } from '@/utils';
export const useFetchListDataProps = {
formData: Object,
loadStatus: Object,
listData: Object,
getData: Function,
onRefresh: Function,
onLoadMore: Function,
genItemData: Function,
}
export const useFetchListData = ({
formData,
requestApi,
handleFormData,
}) => {
const listData = reactive({
data: [],
nextPageUrl: null,
});
const nextPageUrl = toRef(listData, 'nextPageUrl');
const loadStatus = reactive({
loading: false,
error: false,
finished: false,
refreshing: false,
});
const getData = async (url = '') => {
let _formData = {...cloneDeep(formData)};
if(handleFormData){
_formData = handleFormData(_formData);
}
if (!url) {
loadStatus.finished = false;
_formData.page = 1;
nextPageUrl.value = null;
}
try {
const res = await requestApi(_formData, {url, unUseData: !!url});
const resData = res.data.data;
const _listData = resData.data;
listData.data = url ? [...listData.data, ..._listData] : _listData;
nextPageUrl.value = resData.next_page_url;
loadStatus.finished = !resData.next_page_url;
} catch (error) {
nextPageUrl.value = url;
loadStatus.error = true;
Loger.error(error)
} finally {
loadStatus.loading = false;
}
}
const onRefresh = async () => {
try {
await getData();
} catch (error) {
toast('请求失败,点击重试');
Loger.error(error)
} finally {
loadStatus.refreshing = false;
}
};
const onLoadMore = debounce(async () => {
let nextPage = nextPageUrl.value;
if (!nextPage){
loadStatus.loading = false;
return
};
nextPageUrl.value = null;
await getData(nextPage);
}, 100, {
'leading': true,
'trailing': false
});
// 自动获取数据
// watch([formData], (value, preVal) => {
// getData();
// })
return {
formData,
loadStatus,
listData,
getData,
onRefresh,
onLoadMore,
}
}
Loger.error()将日志打印再Console控制台。参考
URL.createObjectURL(obj)可以获取当前文件的一个内存URL,同步执行。需手动使用revokeObjectURL等释放内存。参考
使用render函数
<template>
<div>
<renderMomentList />
</div>
</template>
import { h } from "vue";
import { MomentList } from './components';
组件通信(defineProps、defineEmits、defineExpose)
vue3中使用$refs
有时候想访问$refs绑定的组件的属性或者方法,我们会使用$refs。但是Vue3不同于Vue2,在 Vue3的setup中我们是无法访问到this。
//<div class='poster-container' ref="poster"></div>
const poster = ref();
poster.value; //即可获得,等价于vue2的this.$refs.poster;
js逻辑
Loger.error(error)
var u = navigator.userAgent;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
var isiOS = !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
vue中assets与static的区别
append()与appendChild()和 innerHTML 的区别
插件/组件库
vue动态生成二维码
- 安装:
npm install qrcode --save - 引入:
import QRCode from 'qrcode'; - 使用:
const pageQrcode = ref('');
const getPageQrcode = id => {
if (!id) {
Toast('未获得本人id!');
return;
}
let linkurl =
window.location.href+'/h5/card/index?id=' + id;
QRCode.toDataURL(linkurl)
.then(url => {
pageQrcode.value = url;
})
.catch(err => {
console.error(err);
});
};
pc后台管理(vue2)有用到qrcodejs2;
//html
<div class="qrcode-box" ref="qrCodeUrl"></div>
seeDetail(id){
this.dialogVisible = true;
//会发现页面中会不断声生成二维码,而且新生成的二维码会排在以前二维码的下面。也就是说新生成的二维码并没有替换掉之前的二维码
this.$refs.qrCodeUrl.innerHTML = ""//将之前的二维码清空了
let url = window.location.origin + '/activity/'+id+'/detail';
let qrcodeRef = new QrCode(this.$refs.qrCodeUrl, {
width: 250,
height: 250,
text: url,
colorLight:'#ffffff',//二维码背景色
colorDark:'#F7382B',//二维码前景色,以实现红码为例
correctLevel: QRCode.CorrectLevel.H//纠错等级
});
},
css样式
动态更换主题颜色
// @/less/theme.less
:root {
--bg-color: #008AFF;
--button-active-cover: #008AFF;
--button-color: #008AFF;
}
使用:
background: var(--bg-color);
修改 vant 的默认样式
- 先使用ConfigProvider组件包裹要修改的另一组件,
- 然后再使用
::v-deep修改默认样式即可。
<!-- 分享面板 -->
<ConfigProvider>
<ShareSheet
title="分享至"
v-model:show="showShare"
:options="options"
/>
</ConfigProvider>
::v-deep .van-share-sheet__title {
font-size: 1.68rem;
color: #1A171A;
line-height: 2.56rem;
}
vue 解决ios15适配 input框出现两个放大镜的问题
需求:构建h5搜索框,input回车自动搜索框,type=search后键盘上会出现搜索/search键。
<form action="" @submit.prevent="searchSub">
<div class='input-box'>
<img class='the-search-ico' src='@/assets/search.png'>
<input type="search" class='search-input' v-model="formData.keyword" placeholder="请输入团队/成员名进行检索">
<img v-if="formData.keyword" @click='deleBtn' class='dele-ico' src='@/assets/close.png'>
<!-- <div class='search-btn' @click='searchSub'>搜索</div> -->
</div>
</form>
由于search类型的input自带了搜索标识“🔍”和清除标识"X",如果有自定义样式需要的可以添加如下样式代码,然后自定义搜索框样式
input[type=search]::-webkit-search-cancel-button{
-webkit-appearance: none;/* 此处只是去掉默认的小× */
}
/deep/input[type="search"]{
-webkit-appearance:none !important;
}
ios应用内嵌h5页面数据自动变色识别为手机号码的解决方法
添加如下meta标签,即可解决:
<meta name="format-detection" content="telephone=no">
format-detection —— 格式检测,用来检测html里的一些格式,
主要有以下几个设置:
- meta name=”format-detection” content=”telephone=no”
- meta name=”format-detection” content=”email=no”
- meta name=”format-detection” content=”adress=no”
或者直接写成:
meta name=”format-detection” content=”telephone=no,email=no,adress=no”
telephone
主要作用是是否设置自动将你的数字转化为拨号连接
telephone=no 禁止把数字转化为拨号链接
telephone=yes 开启把数字转化为拨号链接,默认开启
email
告诉设备不识别邮箱,点击之后不自动发送
email=no 禁止作为邮箱地址
email=yes 开启把文字默认为邮箱地址,默认情况开启
adress
adress=no 禁止跳转至地图
不常用的css
user-select 属性规定是否能选取元素的文本。
在 web 浏览器中,如果您在文本上双击,文本会被选取或高亮显示。此属性用于阻止这种行为。
user-select: auto|none|text|all;
运算符 !! 与 && 用法
1. !!运算符
!为逻辑非运算符。它可以将变量取反转换成Boolean型,像0、undefined、''、null这种名义上为否的变量取反都为true,其余的用!为false。
!! 为逻辑非的取反运算符。通常用来做类型判断,就是双重否定等于肯定的意思。
例子:判断flag为非空,定义或者非空串时执行fn函数。
新手写法:
let flag;
...
if(flag != null && typeOf(flag) != undefined && flag != ''){
fn();
}
大佬写法:
if(!!flag){
read();
}
2. &&运算符
- && 取与/并且的意思,常用含义,即两边条件同时成立,即执行后面代码。
- && 后面加运算表达式,表示前面条件成立则执行后面表达式。
例子:如果a!=1,则让a等于1
新手写法:
if(a!=1){
a=1
}
大佬写法:
(!a==1)&&(a=1)
element-ui问题
popover嵌套操作在table列表中的使用
官方文档用的是v-model绑定一个布尔值来控制是否显示,但如果在tablev-for列表中无法同时绑定多个,导致其无法正常使用。
解决方法:
display: table
(参考文献)
1. 基本使用
目前,在大多数开发环境中,已经基本不用table元素来做网页布局了,取而代之的是div+css,那么为什么不用table系表格元素呢?
1、用DIV+CSS编写出来的文件k数比用table写出来的要小,不信你在页面中放1000个table和1000个div比比看哪个文件大
2、table必须在页面完全加载后才显示,没有加载完毕前,table为一片空白,也就是说,需要页面完毕才显示,而div是逐行显示,不需要页面完全加载完毕,就可以一边加载一边显示
3、非表格内容用table来装,不符合标签语义化要求,不利于SEO
4、table的嵌套性太多,用DIV代码会比较简洁
但是有的项目中又需要类似表格的布局怎么办呢?可以用display:table来解决
2. 让块级标签实现行内效果,即浮动至同一横轴,并实现等高效果
table表格中的单元格最大的特点之一就是同一行列表元素都等高。所以,很多时候,我们需要等高布局的时候,就可以借助display:table-cell属性。说到table-cell的布局,不得不说一下“匿名表格元素创建规则”:
CSS2.1表格模型中的元素,可能不会全部包含在除HTML之外的文档语言中。这时,那些“丢失”的元素会被模拟出来,从而使得表格模型能够正常工作。所有的表格元素将会自动在自身周围生成所需的匿名table对象,使其符合table/inline-table、table-row、table- cell的三层嵌套关系。
举个例子吧,如果我们为元素使用“display:table-cell;”属性,而不将其父容器设置为“display:table-row;”属性,浏览器会默认创建出一个表格行,就好像文档中真的存在一个被声明的表格行一样。
3. 结合vertical-align: middle;实现块级元素垂直居中
video 七牛云的视频链接设置封面展示
此方法取视频的第几帧。最后的3表示取视频的第三帧,可直接写在video标签里,其中item.url是视频地址。(默认取第一帧为封面)
<video
...
:poster="item.url + '?vframe/jpg/offset/3'"
></video>