xingfu_h5项目总结

203 阅读7分钟

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});
})

拓展:

  1. 表单清空:

    • 可以在定义reactive数据的时候再定义一个reset:const resetForm = reactive({...dataForm});
    • 这样清空数据的时候就可以这样使用:Object.assign(dataForm,resetFrom);
  2. 为何对象重新赋值后,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动态生成二维码

  1. 安装:npm install qrcode --save
  2. 引入:import QRCode from 'qrcode';
  3. 使用:
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 的默认样式

  1. 先使用ConfigProvider组件包裹要修改的另一组件,
  2. 然后再使用::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键。

image.png

 <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. &&运算符

  1. && 取与/并且的意思,常用含义,即两边条件同时成立,即执行后面代码。
  2. && 后面加运算表达式,表示前面条件成立则执行后面表达式。

例子:如果a!=1,则让a等于1

新手写法:

if(a!=1){
    a=1
}

大佬写法:

(!a==1)&&(a=1)

element-ui问题

popover嵌套操作在table列表中的使用

官方文档用的是v-model绑定一个布尔值来控制是否显示,但如果在tablev-for列表中无法同时绑定多个,导致其无法正常使用。 image.png

解决方法:

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来解决

image.png

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>