Vue3?重構(gòu)函數(shù)透?jìng)魇纠馕?/h1>
更新時(shí)間:2023年02月17日 11:48:24 作者:SoaringHeart
這篇文章主要為大家介紹了Vue3?重構(gòu)函數(shù)透?jìng)魇纠馕?/div>
一、來源
之前做 vue 手機(jī)端需求開發(fā)時(shí),遇到多個(gè)相似列表頁面:
列表頁面+下拉刷新和上拉加載+占位圖(無數(shù)據(jù)+斷網(wǎng))...
就想能不能復(fù)用同一個(gè)頁面,傳入不同的數(shù)據(jù)和單元格即可;經(jīng)過一個(gè)多月的思考(查詢js 的特性 + Vue3官方文檔),最終在官方文檔:

找到解決辦法: 屬性透?jìng)鞣椒?/strong>
原理如下:

二、使用示例
1、VRefreshListDemo.vue
<template>
<navbar
class="navbar"
isleftarrow
navBarTitle="數(shù)據(jù)透?jìng)?
closeWebview
isFixed
/>
<VRefreshList
:requestFC="requestFC"
:requestErrorFC="requestErrorFC"
:requestParamsChange="tag"
:pageIndexInitial="pageIndexInitial"
>
<template v-slot="slotProps">
<MessageInteractiveCell
class="page-view__cell"
v-for="(e, index) in slotProps.list" :key="index"
:imgUrl="deliverDataObj(e)?.activityUserIcon"
:imgUrlRight="getResizedAliOSSImageUrl(e, 64)"
:text="formatContentTitle(e)"
:detailText="formatContentDetails(e)"
:tag="formatDateNoYear(e.pushTime)"
@click="clickCell(e)"
>
</MessageInteractiveCell>
</template>
</VRefreshList>
</template>
<script setup>
import navbar from '@/components/navbar.vue';
import VRefreshList from './VRefreshList.vue';
import MessageInteractiveCell from '@/views/message/components/MessageInteractiveCell.vue';
import { getCurrentInstance, ref, reactive, computed, watch, onMounted, onActivated} from 'vue';
import { onBeforeRouteLeave } from 'vue-router';
import { Toast } from 'vant';
import { useStore } from 'vuex';
import { DropdownMenu, DropdownItem } from 'vant';
import { NET_MSG_ERROR } from '@/service/request/apiMessage';
import { hasNet, goToPage, goToPageForResult } from '@/utils/uplusApi';
import * as RQ from '@/service/request/request.js';
import * as MessageContant from '@/views/message/MessageContant.js';
import {
formatDateWithYear,
formatDateNoYear,
jumpURL,
getResizedAliOSSImageUrl,
deliverDataObj,
} from '@/views/message/MessageCommonUtil';
import icon_interactive from '@/assets/images/icon_interactive_base64';
import icon_like from '@/assets/images/icon_like_base64';
import icon_evaluation from '@/assets/images/icon_evaluation_base64';
const store = useStore();
const currentInstance = getCurrentInstance();
const { $platform, $vtoast, $debounce, $gio} = currentInstance.appContext.config.globalProperties;
onBeforeRouteLeave(() => {
$vtoast.clear();
});
// 初始創(chuàng)建頁面剛進(jìn)來加載一次
onMounted(() => {
// console.log('MessageList -> onMounted');
// $vtoast.loading({});
// onRefresh();
});
onActivated(() => {
console.log('ContentList.vue -> onActivated');
// $vtoast.loading({});
// onMore();
});
const businessType = ref(store.getters.msgType || '0');
const pageIndexInitial = ref(1);
/// 獲取歷史消息
async function requestFC(options) {
const {isRefresh, page, pageSize, lastObj} = options;
console.log(`VRefreshListDemo requestFC:${JSON.stringify(isRefresh)},${page}`);
const timestamp = Date.now();
let msgTime = formatDateWithYear(timestamp);
if (!isRefresh && lastObj) {
msgTime = lastObj.pushTime;
}
const params = {
msgTime: msgTime,
queryTag: 1,
querySize: pageSize,
businessType: businessType.value,
};
if (['20'].includes(businessType.value) &&
store.getters.msgBelong &&
store.getters.msgBelongType) {
params.belong = store.getters.msgBelong;
params.belongType = store.getters.msgBelongType;
}
const items = await RQ.getMsgHistory(params);
return items;
}
async function requestErrorFC(error) {
Toast(JSON.stringify(error));
}
const clickCell = (obj) => {
if (!hasNet.value) {
Toast(NET_MSG_ERROR);
return;
}
const url = formatContentReviewPage(obj);
jumpURL(url);
};
function formatContentTitle(e) {
const activityUserObj = deliverDataObj(e);
// const result = decodeURIComponent(activityUserObj?.activityUserNickName ?? '');
const result = decodeURIComponent(e.message.data.body.view?.title ?? '-');
return result;
}
function formatContentDetails(e) {
const result = decodeURIComponent(e.message.data.body.view?.title ?? '-');
return result;
}
function formatContentReviewPage(e) {
const result = e.message.data.body.extData?.reviewPage;
return result;
}
</script>
<style scoped lang='scss'>
.page-view{
position: relative;
margin-top: 46px;
height: calc(100vh - 46px);
overflow: scroll;
}
.navbar{
height: 46px;
}
:deep .van-pull-refresh{
top: 46px;
}
</style>
2、VRefreshList.vue 源碼
VRefreshCustom 是“上拉刷新和下拉加載+占位圖”的封裝
<template>
<VRefreshCustom
v-model:refreshing="refreshing"
v-model:loading="loading"
:onRefresh="onRefresh"
:loadMore="onMore"
:finished="finished"
:loadingText="loadingText"
:finishedText="finishedText"
:netStatus="netStatus"
:clickVNet="clickVNet"
:isSuccess="isSuccess"
>
<slot :list="list"></slot>
</VRefreshCustom>
</template>
<script setup>
import VRefreshCustom from './VRefreshCustomNew.vue';
import { getCurrentInstance, ref, reactive, computed, watch, onMounted, onActivated} from 'vue';
import { onBeforeRouteLeave } from 'vue-router';
import { Toast } from 'vant';
import { NET_MSG_ERROR } from '@/service/request/apiMessage';
import { hasNet, goToPage, goToPageForResult } from '@/utils/uplusApi';
const currentInstance = getCurrentInstance();
const { $platform, $vtoast, } = currentInstance.appContext.config.globalProperties;
onBeforeRouteLeave(() => {
$vtoast.clear();
console.log('離開 MessageInteractivePage.vue');
});
const props = defineProps({
requestFC: {
type: Function,
required: true,
description: '接口請(qǐng)求方法',
},
requestErrorFC: {
type: Function,
description: '接口請(qǐng)求錯(cuò)誤回調(diào)方法',
},
pageIndexInitial: {
type: Number,
default: 1,
},
pageSize: {
type: Number,
default: 30,
},
requestParamsChange: {
type: String,
},
loadingText: {
type: String,
default: '',
},
finishedText: {
type: String,
default: '',
},
});
const pageIndex = ref(props.pageIndexInitial);
const refreshing = ref(false);
const isSuccess = ref(false);
const loading = ref(false);
const finished = ref(false);
/// -1 請(qǐng)求失敗; 0無數(shù)據(jù); 1 正常列表,有數(shù)據(jù);
const netStatus = ref(1);
const list = reactive([]);
const clickVNet = () => {
$vtoast.loading({});
onRefresh();
};
///下拉刷新
const onRefresh = async () => {
console.log('VRefreshList onRefresh');
pageIndex.value = props.pageIndexInitial;
if (!hasNet.value) {
// netStatus.value = -1;
refreshing.value = false;// 下拉刷新加載狀態(tài)結(jié)束
isSuccess.value = false;// 下拉刷新成功失敗
loading.value = false;// 加載狀態(tài)結(jié)束
finished.value = true;// 數(shù)據(jù)全部加載完成
$vtoast.clear();
Toast(NET_MSG_ERROR);
return;
}
refreshing.value = true;
loading.value = false;
requestList(true);
};
// 上拉獲取更多
const onMore = async () => {
console.log('VRefreshList onMore');
pageIndex.value++;
refreshing.value = false;
loading.value = true;
requestList(false);
};
/// 獲取歷史消息
const requestList = async () => {
try {
netStatus.value = 1;
const params = {
isRefresh: refreshing.value,
page: pageIndex.value,
pageSize: props.pageSize,
lastObj: list.length > 0 ? list[list.length - 1] : undefined,
};
const items = await props.requestFC(params);
// console.log(`VRefreshList items:${items.length}`);
if (refreshing.value) {
list.splice(0, list.length);
}
if (list.length === 0 && items.length === 0) {
refreshing.value = false;
isSuccess.value = true;
loading.value = false;// 加載狀態(tài)結(jié)束
finished.value = true;// 數(shù)據(jù)全部加載完成
netStatus.value = 0;
return;
}
if (items.length) {
list.push(...items);
}
console.log(`${location.hash} list:${list.length}, items:${items.length}`);
loading.value = false;// 加載狀態(tài)結(jié)束
finished.value = (items.length < props.pageSize);// 數(shù)據(jù)全部加載完成
if(refreshing.value){
isSuccess.value = true;
}
netStatus.value = list.length === 0 ? 0 : 1;
} catch (error) {
console.log(`${location.hash} error: ${JSON.stringify(error)},
refreshing: ${refreshing.value},
hasNet.value:${hasNet.value}`);
finished.value = true;// 數(shù)據(jù)全部加載完成
isSuccess.value = false;// 下拉刷新成功失敗
if (!hasNet.value) {
netStatus.value = -1;
} else {
netStatus.value = 0;
}
if (!error) {
return;
}
props.requestErrorFC && await props.requestErrorFC(error);
} finally {
$vtoast.clear();
refreshing.value = false;
loading.value = false;// 加載狀態(tài)結(jié)束
}
};
watch(() => props.requestParamsChange, (newValue, oldValue) => {
console.log('watch requestParamsChange', newValue, oldValue);
if (newValue !== oldValue) {
scrollToTop(listEl);
onRefresh();
}
});
watch(() => hasNet.value, (newValue, oldValue) => {
// console.log('hasNet.value', newValue, oldValue);
if (newValue) {
onRefresh();
}
});
let listEl;
onMounted(() => {
listEl = document.getElementById('van-list');
// console.log(listEl);
});
const scrollToTop = (e) => e.scrollIntoView({ block: 'start' });
</script>
最后、總結(jié)
1、此文重構(gòu)方法的意義在于我可以通過封裝一個(gè)列表組件,然后同類頁面只需要傳請(qǐng)求方法即可,極大的提高開發(fā)效率(vue 中組件亦可是頁面);
2、核心是通過 Vue3 屬性支持 Function 進(jìn)而實(shí)現(xiàn)函數(shù)透?jìng)?,雖然官方文檔只是一筆帶過,但確實(shí)是核心特性之一;
3、Function 類型無論在 Swift、Dart/Flutter、JS/TS 中都是一等公民;可以幫助我們擴(kuò)展代碼重構(gòu)邊界。在實(shí)現(xiàn)此次封裝之前我也不知道能做到什么程度,不過最終效果非常理想;
4、姐妹篇 Flutter 重構(gòu): 屬性透?jìng)?函數(shù)透?jìng)?/a>
以上就是Vue3 重構(gòu)函數(shù)透?jìng)魇纠馕龅脑敿?xì)內(nèi)容,更多關(guān)于Vue3 重構(gòu)函數(shù)透?jìng)鞯馁Y料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
-
vue實(shí)現(xiàn)過渡動(dòng)畫Message消息提示組件示例詳解
這篇文章主要為大家介紹了vue實(shí)現(xiàn)過渡動(dòng)畫Message消息提示組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪 2022-07-07
-
vue項(xiàng)目配置sass及引入外部scss文件方式
這篇文章主要介紹了vue項(xiàng)目配置sass及引入外部scss文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教 2022-04-04
-
vue+elemet實(shí)現(xiàn)表格手動(dòng)合并行列
這篇文章主要為大家詳細(xì)介紹了vue+elemet實(shí)現(xiàn)表格手動(dòng)合并行列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 2022-08-08
-
Vue單頁及多頁應(yīng)用全局配置404頁面實(shí)踐記錄
無論單頁還是多頁,我的實(shí)現(xiàn)思路是總體配置404頁面的思路就是在前端路由表中添加一個(gè) path: '/404' 的路由,渲染相應(yīng)的404頁面。這篇文章主要介紹了Vue單頁及多頁應(yīng)用全局配置404頁面實(shí)踐,需要的朋友可以參考下 2018-05-05
-
ElementUI中的el-dropdown傳入多參數(shù)的實(shí)現(xiàn)方法
本文主要介紹了ElementUI中的el-dropdown傳入多參數(shù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 2021-12-12
-
解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問題
今天小編就為大家分享一篇解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧 2018-09-09
-
vue實(shí)現(xiàn)web前端登錄頁數(shù)字驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)web前端登錄頁數(shù)字驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
2022-06-06
最新評(píng)論
一、來源
之前做 vue 手機(jī)端需求開發(fā)時(shí),遇到多個(gè)相似列表頁面:
列表頁面+下拉刷新和上拉加載+占位圖(無數(shù)據(jù)+斷網(wǎng))...
就想能不能復(fù)用同一個(gè)頁面,傳入不同的數(shù)據(jù)和單元格即可;經(jīng)過一個(gè)多月的思考(查詢js 的特性 + Vue3官方文檔),最終在官方文檔:
找到解決辦法: 屬性透?jìng)鞣椒?/strong>
原理如下:
二、使用示例
1、VRefreshListDemo.vue
<template> <navbar class="navbar" isleftarrow navBarTitle="數(shù)據(jù)透?jìng)? closeWebview isFixed /> <VRefreshList :requestFC="requestFC" :requestErrorFC="requestErrorFC" :requestParamsChange="tag" :pageIndexInitial="pageIndexInitial" > <template v-slot="slotProps"> <MessageInteractiveCell class="page-view__cell" v-for="(e, index) in slotProps.list" :key="index" :imgUrl="deliverDataObj(e)?.activityUserIcon" :imgUrlRight="getResizedAliOSSImageUrl(e, 64)" :text="formatContentTitle(e)" :detailText="formatContentDetails(e)" :tag="formatDateNoYear(e.pushTime)" @click="clickCell(e)" > </MessageInteractiveCell> </template> </VRefreshList> </template> <script setup> import navbar from '@/components/navbar.vue'; import VRefreshList from './VRefreshList.vue'; import MessageInteractiveCell from '@/views/message/components/MessageInteractiveCell.vue'; import { getCurrentInstance, ref, reactive, computed, watch, onMounted, onActivated} from 'vue'; import { onBeforeRouteLeave } from 'vue-router'; import { Toast } from 'vant'; import { useStore } from 'vuex'; import { DropdownMenu, DropdownItem } from 'vant'; import { NET_MSG_ERROR } from '@/service/request/apiMessage'; import { hasNet, goToPage, goToPageForResult } from '@/utils/uplusApi'; import * as RQ from '@/service/request/request.js'; import * as MessageContant from '@/views/message/MessageContant.js'; import { formatDateWithYear, formatDateNoYear, jumpURL, getResizedAliOSSImageUrl, deliverDataObj, } from '@/views/message/MessageCommonUtil'; import icon_interactive from '@/assets/images/icon_interactive_base64'; import icon_like from '@/assets/images/icon_like_base64'; import icon_evaluation from '@/assets/images/icon_evaluation_base64'; const store = useStore(); const currentInstance = getCurrentInstance(); const { $platform, $vtoast, $debounce, $gio} = currentInstance.appContext.config.globalProperties; onBeforeRouteLeave(() => { $vtoast.clear(); }); // 初始創(chuàng)建頁面剛進(jìn)來加載一次 onMounted(() => { // console.log('MessageList -> onMounted'); // $vtoast.loading({}); // onRefresh(); }); onActivated(() => { console.log('ContentList.vue -> onActivated'); // $vtoast.loading({}); // onMore(); }); const businessType = ref(store.getters.msgType || '0'); const pageIndexInitial = ref(1); /// 獲取歷史消息 async function requestFC(options) { const {isRefresh, page, pageSize, lastObj} = options; console.log(`VRefreshListDemo requestFC:${JSON.stringify(isRefresh)},${page}`); const timestamp = Date.now(); let msgTime = formatDateWithYear(timestamp); if (!isRefresh && lastObj) { msgTime = lastObj.pushTime; } const params = { msgTime: msgTime, queryTag: 1, querySize: pageSize, businessType: businessType.value, }; if (['20'].includes(businessType.value) && store.getters.msgBelong && store.getters.msgBelongType) { params.belong = store.getters.msgBelong; params.belongType = store.getters.msgBelongType; } const items = await RQ.getMsgHistory(params); return items; } async function requestErrorFC(error) { Toast(JSON.stringify(error)); } const clickCell = (obj) => { if (!hasNet.value) { Toast(NET_MSG_ERROR); return; } const url = formatContentReviewPage(obj); jumpURL(url); }; function formatContentTitle(e) { const activityUserObj = deliverDataObj(e); // const result = decodeURIComponent(activityUserObj?.activityUserNickName ?? ''); const result = decodeURIComponent(e.message.data.body.view?.title ?? '-'); return result; } function formatContentDetails(e) { const result = decodeURIComponent(e.message.data.body.view?.title ?? '-'); return result; } function formatContentReviewPage(e) { const result = e.message.data.body.extData?.reviewPage; return result; } </script> <style scoped lang='scss'> .page-view{ position: relative; margin-top: 46px; height: calc(100vh - 46px); overflow: scroll; } .navbar{ height: 46px; } :deep .van-pull-refresh{ top: 46px; } </style>
2、VRefreshList.vue 源碼
VRefreshCustom 是“上拉刷新和下拉加載+占位圖”的封裝
<template> <VRefreshCustom v-model:refreshing="refreshing" v-model:loading="loading" :onRefresh="onRefresh" :loadMore="onMore" :finished="finished" :loadingText="loadingText" :finishedText="finishedText" :netStatus="netStatus" :clickVNet="clickVNet" :isSuccess="isSuccess" > <slot :list="list"></slot> </VRefreshCustom> </template> <script setup> import VRefreshCustom from './VRefreshCustomNew.vue'; import { getCurrentInstance, ref, reactive, computed, watch, onMounted, onActivated} from 'vue'; import { onBeforeRouteLeave } from 'vue-router'; import { Toast } from 'vant'; import { NET_MSG_ERROR } from '@/service/request/apiMessage'; import { hasNet, goToPage, goToPageForResult } from '@/utils/uplusApi'; const currentInstance = getCurrentInstance(); const { $platform, $vtoast, } = currentInstance.appContext.config.globalProperties; onBeforeRouteLeave(() => { $vtoast.clear(); console.log('離開 MessageInteractivePage.vue'); }); const props = defineProps({ requestFC: { type: Function, required: true, description: '接口請(qǐng)求方法', }, requestErrorFC: { type: Function, description: '接口請(qǐng)求錯(cuò)誤回調(diào)方法', }, pageIndexInitial: { type: Number, default: 1, }, pageSize: { type: Number, default: 30, }, requestParamsChange: { type: String, }, loadingText: { type: String, default: '', }, finishedText: { type: String, default: '', }, }); const pageIndex = ref(props.pageIndexInitial); const refreshing = ref(false); const isSuccess = ref(false); const loading = ref(false); const finished = ref(false); /// -1 請(qǐng)求失敗; 0無數(shù)據(jù); 1 正常列表,有數(shù)據(jù); const netStatus = ref(1); const list = reactive([]); const clickVNet = () => { $vtoast.loading({}); onRefresh(); }; ///下拉刷新 const onRefresh = async () => { console.log('VRefreshList onRefresh'); pageIndex.value = props.pageIndexInitial; if (!hasNet.value) { // netStatus.value = -1; refreshing.value = false;// 下拉刷新加載狀態(tài)結(jié)束 isSuccess.value = false;// 下拉刷新成功失敗 loading.value = false;// 加載狀態(tài)結(jié)束 finished.value = true;// 數(shù)據(jù)全部加載完成 $vtoast.clear(); Toast(NET_MSG_ERROR); return; } refreshing.value = true; loading.value = false; requestList(true); }; // 上拉獲取更多 const onMore = async () => { console.log('VRefreshList onMore'); pageIndex.value++; refreshing.value = false; loading.value = true; requestList(false); }; /// 獲取歷史消息 const requestList = async () => { try { netStatus.value = 1; const params = { isRefresh: refreshing.value, page: pageIndex.value, pageSize: props.pageSize, lastObj: list.length > 0 ? list[list.length - 1] : undefined, }; const items = await props.requestFC(params); // console.log(`VRefreshList items:${items.length}`); if (refreshing.value) { list.splice(0, list.length); } if (list.length === 0 && items.length === 0) { refreshing.value = false; isSuccess.value = true; loading.value = false;// 加載狀態(tài)結(jié)束 finished.value = true;// 數(shù)據(jù)全部加載完成 netStatus.value = 0; return; } if (items.length) { list.push(...items); } console.log(`${location.hash} list:${list.length}, items:${items.length}`); loading.value = false;// 加載狀態(tài)結(jié)束 finished.value = (items.length < props.pageSize);// 數(shù)據(jù)全部加載完成 if(refreshing.value){ isSuccess.value = true; } netStatus.value = list.length === 0 ? 0 : 1; } catch (error) { console.log(`${location.hash} error: ${JSON.stringify(error)}, refreshing: ${refreshing.value}, hasNet.value:${hasNet.value}`); finished.value = true;// 數(shù)據(jù)全部加載完成 isSuccess.value = false;// 下拉刷新成功失敗 if (!hasNet.value) { netStatus.value = -1; } else { netStatus.value = 0; } if (!error) { return; } props.requestErrorFC && await props.requestErrorFC(error); } finally { $vtoast.clear(); refreshing.value = false; loading.value = false;// 加載狀態(tài)結(jié)束 } }; watch(() => props.requestParamsChange, (newValue, oldValue) => { console.log('watch requestParamsChange', newValue, oldValue); if (newValue !== oldValue) { scrollToTop(listEl); onRefresh(); } }); watch(() => hasNet.value, (newValue, oldValue) => { // console.log('hasNet.value', newValue, oldValue); if (newValue) { onRefresh(); } }); let listEl; onMounted(() => { listEl = document.getElementById('van-list'); // console.log(listEl); }); const scrollToTop = (e) => e.scrollIntoView({ block: 'start' }); </script>
最后、總結(jié)
1、此文重構(gòu)方法的意義在于我可以通過封裝一個(gè)列表組件,然后同類頁面只需要傳請(qǐng)求方法即可,極大的提高開發(fā)效率(vue 中組件亦可是頁面);
2、核心是通過 Vue3 屬性支持 Function 進(jìn)而實(shí)現(xiàn)函數(shù)透?jìng)?,雖然官方文檔只是一筆帶過,但確實(shí)是核心特性之一;
3、Function 類型無論在 Swift、Dart/Flutter、JS/TS 中都是一等公民;可以幫助我們擴(kuò)展代碼重構(gòu)邊界。在實(shí)現(xiàn)此次封裝之前我也不知道能做到什么程度,不過最終效果非常理想;
4、姐妹篇 Flutter 重構(gòu): 屬性透?jìng)?函數(shù)透?jìng)?/a>
以上就是Vue3 重構(gòu)函數(shù)透?jìng)魇纠馕龅脑敿?xì)內(nèi)容,更多關(guān)于Vue3 重構(gòu)函數(shù)透?jìng)鞯馁Y料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue實(shí)現(xiàn)過渡動(dòng)畫Message消息提示組件示例詳解
這篇文章主要為大家介紹了vue實(shí)現(xiàn)過渡動(dòng)畫Message消息提示組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07vue項(xiàng)目配置sass及引入外部scss文件方式
這篇文章主要介紹了vue項(xiàng)目配置sass及引入外部scss文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue+elemet實(shí)現(xiàn)表格手動(dòng)合并行列
這篇文章主要為大家詳細(xì)介紹了vue+elemet實(shí)現(xiàn)表格手動(dòng)合并行列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Vue單頁及多頁應(yīng)用全局配置404頁面實(shí)踐記錄
無論單頁還是多頁,我的實(shí)現(xiàn)思路是總體配置404頁面的思路就是在前端路由表中添加一個(gè) path: '/404' 的路由,渲染相應(yīng)的404頁面。這篇文章主要介紹了Vue單頁及多頁應(yīng)用全局配置404頁面實(shí)踐,需要的朋友可以參考下2018-05-05ElementUI中的el-dropdown傳入多參數(shù)的實(shí)現(xiàn)方法
本文主要介紹了ElementUI中的el-dropdown傳入多參數(shù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問題
今天小編就為大家分享一篇解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09vue實(shí)現(xiàn)web前端登錄頁數(shù)字驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)web前端登錄頁數(shù)字驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06