作品集代码初版
This commit is contained in:
parent
1d113e78ed
commit
475e0461e2
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nav-bar">
|
<div class="nav-bar">
|
||||||
<van-nav-bar title="标题" left-text="返回" :placeholder="true" :safe-area-inset-top="true" z-index="99">
|
<van-nav-bar title="屿" left-text="" :placeholder="true" :safe-area-inset-top="true" z-index="99">
|
||||||
<template #right>
|
<template #right>
|
||||||
<van-icon name="search" size="18" />
|
<van-icon name="search" size="18" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Vuex from 'vuex'
|
import Vuex from "vuex";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import store from "./store";
|
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
import { Tabbar, TabbarItem } from "vant";
|
import { Tabbar, TabbarItem } from "vant";
|
||||||
import { NavBar } from "vant";
|
import { NavBar } from "vant";
|
||||||
import { Toast } from 'vant';
|
import { Toast } from "vant";
|
||||||
import { Popup } from 'vant';
|
import { Popup } from "vant";
|
||||||
import { Icon } from 'vant';
|
import { Icon } from "vant";
|
||||||
import { Button } from 'vant';
|
import { Button } from "vant";
|
||||||
|
import { Image as VanImage } from "vant";
|
||||||
|
import { Lazyload } from "vant";
|
||||||
|
import { Card } from "vant";
|
||||||
|
import { Tag } from "vant";
|
||||||
|
|
||||||
|
Vue.use(Tag);
|
||||||
|
Vue.use(Card);
|
||||||
|
Vue.use(Lazyload);
|
||||||
|
Vue.use(VanImage);
|
||||||
Vue.use(Button);
|
Vue.use(Button);
|
||||||
Vue.use(Icon);
|
Vue.use(Icon);
|
||||||
Vue.use(Popup);
|
Vue.use(Popup);
|
||||||
@ -22,7 +29,6 @@ Vue.use(TabbarItem);
|
|||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
store,
|
|
||||||
router,
|
router,
|
||||||
render: (h) => h(App),
|
render: (h) => h(App),
|
||||||
}).$mount("#app");
|
}).$mount("#app");
|
||||||
|
@ -1,25 +1,284 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="portfolio-page">
|
<div class="container">
|
||||||
<h1>作品集</h1>
|
<div class="card-grid">
|
||||||
|
<!-- 卡片列表 -->
|
||||||
|
<div
|
||||||
|
v-for="(card, index) in cards"
|
||||||
|
:key="index"
|
||||||
|
class="card"
|
||||||
|
:class="{ 'card-active': activeCardIndex === index }"
|
||||||
|
@touchstart="handleTouchStart(index)"
|
||||||
|
@touchend="handleTouchEnd(index)"
|
||||||
|
@click="handleCardClick(card)"
|
||||||
|
>
|
||||||
|
<div class="card-image-container">
|
||||||
|
<img
|
||||||
|
:src="card.image"
|
||||||
|
:alt="card.title"
|
||||||
|
class="card-image"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="card.tag"
|
||||||
|
class="card-tag"
|
||||||
|
:style="card.tagStyle"
|
||||||
|
>
|
||||||
|
{{ card.tag }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<h2 class="card-title">{{ card.title }}</h2>
|
||||||
|
<p class="card-description">{{ card.description }}</p>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<span class="card-meta">
|
||||||
|
<i class="fa fa-calendar-o mr-1"></i> {{ card.duration }}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
class="card-button"
|
||||||
|
@click.stop="handleButtonClick(card)"
|
||||||
|
>
|
||||||
|
了解更多
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "PortfolioPage",
|
name: 'PortfolioPage',
|
||||||
components: {},
|
data() {
|
||||||
props: {},
|
return {
|
||||||
data() {
|
cards: [
|
||||||
return {
|
{
|
||||||
};
|
title: "探索自然之美",
|
||||||
|
description: "深入原始森林,感受大自然的鬼斧神工。这里有清澈的溪流、茂密的树木和各种珍稀野生动物。",
|
||||||
|
image: "https://picsum.photos/seed/card1/600/800",
|
||||||
|
duration: "3天2晚",
|
||||||
|
tag: "热门",
|
||||||
|
tagStyle: {
|
||||||
|
backgroundColor: "#F97316",
|
||||||
|
color: "#fff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "城市探险之旅",
|
||||||
|
description: "穿梭于现代都市与历史古迹之间,体验城市独特的文化氛围和美食特色。",
|
||||||
|
image: "https://picsum.photos/seed/card2/600/800",
|
||||||
|
duration: "2天1晚",
|
||||||
|
tag: "热门",
|
||||||
|
tagStyle: {
|
||||||
|
backgroundColor: "#F97316",
|
||||||
|
color: "#fff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "美食文化体验",
|
||||||
|
description: "跟随当地厨师学习传统美食的制作方法,品尝地道佳肴,感受美食背后的文化故事。",
|
||||||
|
image: "https://picsum.photos/seed/card3/600/800",
|
||||||
|
duration: "1天",
|
||||||
|
tag: "新品",
|
||||||
|
tagStyle: {
|
||||||
|
backgroundColor: "#22c55e",
|
||||||
|
color: "#fff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "海洋生态探索",
|
||||||
|
description: "潜入蔚蓝深海,探索神秘的海底世界,与海龟、珊瑚和热带鱼共舞。",
|
||||||
|
image: "https://picsum.photos/seed/card4/600/800",
|
||||||
|
duration: "4天3晚",
|
||||||
|
tag: "推荐",
|
||||||
|
tagStyle: {
|
||||||
|
backgroundColor: "#3b82f6",
|
||||||
|
color: "#fff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
activeCardIndex: -1
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTouchStart(index) {
|
||||||
|
this.activeCardIndex = index;
|
||||||
},
|
},
|
||||||
watch: {},
|
|
||||||
computed: {
|
handleTouchEnd() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.activeCardIndex = -1;
|
||||||
|
}, 300);
|
||||||
},
|
},
|
||||||
methods: {},
|
|
||||||
created() { },
|
handleCardClick(card) {
|
||||||
mounted() { }
|
console.log('点击了卡片:', card.title);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleButtonClick(card) {
|
||||||
|
console.log('点击了了解更多:', card.title);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 处理按钮触摸反馈
|
||||||
|
const buttons = document.querySelectorAll('.card-button');
|
||||||
|
buttons.forEach(button => {
|
||||||
|
button.addEventListener('touchstart', () => {
|
||||||
|
button.classList.add('button-active');
|
||||||
|
});
|
||||||
|
|
||||||
|
button.addEventListener('touchend', () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
button.classList.remove('button-active');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped></style>
|
|
||||||
|
<style scoped>
|
||||||
|
/* 基础样式 */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: 'Inter', system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f9fafb;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 容器样式 - 限制最大宽度为800px(双列布局的合理宽度) */
|
||||||
|
.container {
|
||||||
|
max-width: 800px; /* 双列布局的最佳最大宽度 */
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.5rem, 3vw, 2rem);
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1f2937;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片网格布局 - 固定双列 */
|
||||||
|
.card-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr); /* 固定双列布局 */
|
||||||
|
gap: 24px; /* 卡片间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端适配 - 屏幕小于600px时改为单列 */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.card-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片样式 */
|
||||||
|
.card {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-active {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片图片 */
|
||||||
|
.card-image-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-image {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
/* 3:4 比例 */
|
||||||
|
aspect-ratio: 3 / 4;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片标签 */
|
||||||
|
.card-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片内容 */
|
||||||
|
.card-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1f2937;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-description {
|
||||||
|
color: #6b7280;
|
||||||
|
text-wrap: balance;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片底部 */
|
||||||
|
.card-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-meta {
|
||||||
|
color: #3b82f6;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式 */
|
||||||
|
.card-button {
|
||||||
|
background-color: #3b82f6;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-button:hover {
|
||||||
|
background-color: #2563eb;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
</style>
|
@ -3,7 +3,6 @@ import VueRouter from "vue-router";
|
|||||||
import HomePage from "@/pages/HomePage.vue";
|
import HomePage from "@/pages/HomePage.vue";
|
||||||
import PortfolioPage from "@/pages/PortfolioPage.vue";
|
import PortfolioPage from "@/pages/PortfolioPage.vue";
|
||||||
import SampleCollectionPage from "@/pages/SampleCollectionPage.vue";
|
import SampleCollectionPage from "@/pages/SampleCollectionPage.vue";
|
||||||
import {store} from "@/store";
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -34,10 +33,6 @@ const router = new VueRouter({
|
|||||||
|
|
||||||
// 全局前置守卫
|
// 全局前置守卫
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// 避免重复记录相同路径(如刷新页面)
|
|
||||||
if (to.path !== from.path) {
|
|
||||||
store.dispatch("routeHistory/pushRoute", to);
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
|
|
||||||
const state = {
|
|
||||||
history: [], // 存储路由历史
|
|
||||||
};
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
// 添加路由到历史记录
|
|
||||||
PUSH_ROUTE(state, route) {
|
|
||||||
state.history.push(route);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 重置历史记录
|
|
||||||
RESET_HISTORY(state) {
|
|
||||||
state.history = [];
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
pushRoute({ commit }, route) {
|
|
||||||
commit("PUSH_ROUTE", route);
|
|
||||||
},
|
|
||||||
|
|
||||||
resetHistory({ commit }) {
|
|
||||||
commit("RESET_HISTORY");
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const getters = {
|
|
||||||
// 判断当前是否为后退操作
|
|
||||||
isBack(state) {
|
|
||||||
if (state.history.length < 2) return false;
|
|
||||||
|
|
||||||
const current = state.history[state.history.length - 1];
|
|
||||||
const previous = state.history[state.history.length - 2];
|
|
||||||
|
|
||||||
// 通过比较路径判断是否为后退
|
|
||||||
return previous.path === current.path;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取历史记录长度
|
|
||||||
historyLength(state) {
|
|
||||||
return state.history.length;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true, // 使用命名空间
|
|
||||||
state,
|
|
||||||
mutations,
|
|
||||||
actions,
|
|
||||||
getters,
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user