Przeglądaj źródła

静态页面搭建

shaogen1995 3 lat temu
rodzic
commit
389f8daf78
49 zmienionych plików z 27054 dodań i 0 usunięć
  1. 23 0
      webM/.gitignore
  2. 19 0
      webM/README.md
  3. 5 0
      webM/babel.config.js
  4. 26006 0
      webM/package-lock.json
  5. 28 0
      webM/package.json
  6. BIN
      webM/public/favicon.ico
  7. 17 0
      webM/public/index.html
  8. 8 0
      webM/src/App.vue
  9. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Bold-2.otf
  10. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-ExtraLight-3.otf
  11. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Heavy-4.otf
  12. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Light-5.otf
  13. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Medium-6.otf
  14. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Regular-1.otf
  15. BIN
      webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-SemiBold-7.otf
  16. 73 0
      webM/src/assets/base.css
  17. BIN
      webM/src/assets/img/arrows.png
  18. BIN
      webM/src/assets/img/back.png
  19. BIN
      webM/src/assets/img/back2.png
  20. BIN
      webM/src/assets/img/bs.png
  21. BIN
      webM/src/assets/img/cBg/1.png
  22. BIN
      webM/src/assets/img/cName/1.png
  23. BIN
      webM/src/assets/img/cancel.png
  24. BIN
      webM/src/assets/img/close.png
  25. BIN
      webM/src/assets/img/daily.png
  26. BIN
      webM/src/assets/img/daily_active.png
  27. BIN
      webM/src/assets/img/data.png
  28. BIN
      webM/src/assets/img/data_active.png
  29. BIN
      webM/src/assets/img/detail.png
  30. BIN
      webM/src/assets/img/gaikuang.png
  31. BIN
      webM/src/assets/img/homeBg.png
  32. BIN
      webM/src/assets/img/introduction.png
  33. BIN
      webM/src/assets/img/introduction_active.png
  34. BIN
      webM/src/assets/img/like.png
  35. BIN
      webM/src/assets/img/like_active.png
  36. BIN
      webM/src/assets/img/number.png
  37. BIN
      webM/src/assets/img/search.png
  38. BIN
      webM/src/assets/img/search2.png
  39. BIN
      webM/src/assets/img/share.png
  40. BIN
      webM/src/assets/img/share_active.png
  41. BIN
      webM/src/assets/img/slide.png
  42. 10 0
      webM/src/main.js
  43. 23 0
      webM/src/router/index.js
  44. 38 0
      webM/src/utils/api.js
  45. 38 0
      webM/src/utils/request.js
  46. 291 0
      webM/src/views/Home.vue
  47. 175 0
      webM/src/views/Search.vue
  48. 88 0
      webM/src/views/stair/component/intro.vue
  49. 212 0
      webM/src/views/stair/index.vue

+ 23 - 0
webM/.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 19 - 0
webM/README.md

@@ -0,0 +1,19 @@
+# webm
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
webM/babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

Plik diff jest za duży
+ 26006 - 0
webM/package-lock.json


+ 28 - 0
webM/package.json

@@ -0,0 +1,28 @@
+{
+  "name": "webm",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build"
+  },
+  "dependencies": {
+    "axios": "^0.27.2",
+    "core-js": "^3.6.5",
+    "vue": "^2.6.11",
+    "vue-router": "^3.2.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.13",
+    "@vue/cli-plugin-router": "~4.5.13",
+    "@vue/cli-service": "~4.5.13",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

BIN
webM/public/favicon.ico


+ 17 - 0
webM/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title>江门市传统村落一张图</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 8 - 0
webM/src/App.vue

@@ -0,0 +1,8 @@
+<template>
+  <div id="app">
+    <Router-view/>
+  </div>
+</template>
+
+<style lang="less">
+</style>

BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Bold-2.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-ExtraLight-3.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Heavy-4.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Light-5.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Medium-6.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-Regular-1.otf


BIN
webM/src/assets/SiYuanSongTiRegular/SourceHanSerifCN-SemiBold-7.otf


+ 73 - 0
webM/src/assets/base.css

@@ -0,0 +1,73 @@
+@font-face {
+  font-family: 'SYST';
+  src: url('./SiYuanSongTiRegular/SourceHanSerifCN-Bold-2.otf');
+  font-weight: normal;
+  font-style: normal;
+}
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+a {
+  text-decoration: none;
+}
+
+ul,
+ol {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+}
+
+/* 移动端图⽚边框相当于  border:0 */
+img {
+  vertical-align: top;
+}
+
+/* -webkit-tap-highlight-color:rgba(0,0,0,0);//透明度设置为0,去掉点击链接和⽂本框对象时默认的灰⾊半透明覆盖层(iOS)或者虚框(Android)  */
+a,
+input,
+button {
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+/* 取消chrome下默认的⽂本框聚焦样式 */
+input,
+textarea {
+  outline: none
+}
+
+/* 去掉IOS移除原⽣控件样式 */
+/* -webkit-appearance: none; */
+/* 消除输⼊框和按钮的原⽣外观,在iOS上加上这个属性才能给按钮和输⼊框⾃定义样式  */
+input,
+button {
+  -webkit-appearance: none;
+  border-radius: 0;
+}
+
+/* -webkit-touch-callout:none;  */
+/* 禁⽤长按页⾯时的弹出菜单 */
+/* -webkit-user-select: none; */
+/* 禁⽌页⾯⽂字选择,此属性不继承,⼀般加在body上规定整个body的⽂字都不会⾃动调整 */
+/* 禁⽌移动端⽤户进⾏复制.选择. */
+body {
+  margin: 0;
+  -webkit-user-select: none;
+  -webkit-touch-callout: none;
+}
+
+body * {
+  -webkit-user-select: none;
+  font-family: Helvetica;
+}
+
+body {
+  -webkit-text-size-adjust: 100%;
+}
+
+/* 移动端横竖屏字体乎⼤乎⼩ */
+/* -webkit-text-size-adjust: none;  */
+/* 禁⽌⽂字⾃动调整⼤⼩(默认情况下旋转设备的时候⽂字⼤⼩会发⽣变化),此属性也不继承,⼀般加在body上规定整个body的⽂字都不会⾃动调整  */

BIN
webM/src/assets/img/arrows.png


BIN
webM/src/assets/img/back.png


BIN
webM/src/assets/img/back2.png


BIN
webM/src/assets/img/bs.png


BIN
webM/src/assets/img/cBg/1.png


BIN
webM/src/assets/img/cName/1.png


BIN
webM/src/assets/img/cancel.png


BIN
webM/src/assets/img/close.png


BIN
webM/src/assets/img/daily.png


BIN
webM/src/assets/img/daily_active.png


BIN
webM/src/assets/img/data.png


BIN
webM/src/assets/img/data_active.png


BIN
webM/src/assets/img/detail.png


BIN
webM/src/assets/img/gaikuang.png


BIN
webM/src/assets/img/homeBg.png


BIN
webM/src/assets/img/introduction.png


BIN
webM/src/assets/img/introduction_active.png


BIN
webM/src/assets/img/like.png


BIN
webM/src/assets/img/like_active.png


BIN
webM/src/assets/img/number.png


BIN
webM/src/assets/img/search.png


BIN
webM/src/assets/img/search2.png


BIN
webM/src/assets/img/share.png


BIN
webM/src/assets/img/share_active.png


BIN
webM/src/assets/img/slide.png


+ 10 - 0
webM/src/main.js

@@ -0,0 +1,10 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+
+Vue.config.productionTip = false
+import './assets/base.css'
+new Vue({
+  router,
+  render: h => h(App)
+}).$mount('#app')

+ 23 - 0
webM/src/router/index.js

@@ -0,0 +1,23 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+
+Vue.use(VueRouter)
+
+const routes = [
+  {
+    path: '/',
+    name: 'Home',
+    component: () => import( '../views/Home.vue')
+  },
+  {
+    path: '/stair/:id',
+    name: 'stair',
+    component: () => import( '../views/stair/index.vue')
+  },
+]
+
+const router = new VueRouter({
+  routes
+})
+
+export default router

+ 38 - 0
webM/src/utils/api.js

@@ -0,0 +1,38 @@
+import axios from './request'
+// 村庄保存点赞
+export const likeSaveApi = (villageId) => {
+  return axios({
+    method: 'get',
+    url: `/web/village/addStar/${villageId}`,
+  })
+}
+// 村庄浏览量
+export const lookSaveApi = (villageId) => {
+  return axios({
+    method: 'get',
+    url: `/web/village/addVisit/${villageId}`,
+  })
+}
+// 获取浏览量和点赞量
+export const getCunNumApi = (villageId) => {
+  return axios({
+    method: 'get',
+    url: `/web/village/getDetail/${villageId}`,
+  })
+}
+
+// 获取菜单树
+export const getTreeMenuApi = () => {
+  return axios({
+    method: 'get',
+    url: '/web/getTreeMenu',
+  })
+} 
+
+// 获取内容列表
+export const getInfoApi = (villageId) => {
+  return axios({
+    method: 'get',
+    url: `/web/content/list/${villageId}`,
+  })
+}

+ 38 - 0
webM/src/utils/request.js

@@ -0,0 +1,38 @@
+import axios from 'axios'
+const service = axios.create({
+  baseURL: 'http://192.168.0.135:8016', // 本地调试
+  // baseURL: '', // 线上调试
+  // baseURL: '', // build
+  timeout: 5000
+})
+// 请求拦截器
+service.interceptors.request.use(function (config) {
+  // console.log('触发拦截器')
+  // 在发送请求之前做些什么:看看有没有token,如果有通过请求头的方式传递token
+  const token = localStorage.getItem('JMYZU_token')
+  if (token) { // 判断是否有token,有,则
+    // config.headers['Authorization'] = token
+    config.headers.token = token
+  }
+
+  return config
+}, function (error) {
+  // 对请求错误做些什么
+  return Promise.reject(error)
+})
+
+// 添加响应拦截器
+service.interceptors.response.use(function (response) {
+  // console.log('触发相应拦截器', response)
+  // 对响应数据做点什么--response就是发送每个请求的返回值
+  // if (response.data.code === 5001 || response.data.code === 5002) {
+  //   // Toast.fail('未登录,请先登录')
+  //   localStorage.removeItem('JMYZU_token')
+  // }
+  return response.data
+}, function (error) {
+  // 对响应错误做点什么
+  return Promise.reject(error)
+})
+
+export default service

+ 291 - 0
webM/src/views/Home.vue

@@ -0,0 +1,291 @@
+<template>
+  <div class="Home">
+    <div class="map">地图页面,等待开发...</div>
+    <!-- 顶部 -->
+    <div class="top" :class="{ topOpen: cutArrows }">
+      <!-- 箭头 -->
+      <img
+        class="arrowsImg"
+        @click="cutArrows = !cutArrows"
+        src="../assets/img/arrows.png"
+        alt=""
+      />
+      <div class="arrows" @click="cutArrows = !cutArrows">
+        <div class="arrowsLeft"></div>
+        <div class="arrowsRight"></div>
+      </div>
+      <!-- 标题 -->
+      <div class="tit">
+        <h3>江门市中国传统村落一张图</h3>
+        <img src="../assets/img/search.png" alt=""  @click="searchShow=true"/>
+      </div>
+      <!-- 展开后的内容 -->
+      <div class="main" v-show="cutArrows">
+        <div class="browse">浏览概况</div>
+        <div class="browseNum">
+          <div>
+            <p>累计浏览量</p>
+            <span>1000</span>
+          </div>
+          <div>
+            <p>今日浏览量</p>
+            <span>500</span>
+          </div>
+        </div>
+        <div class="browse browse2">详情统计</div>
+        <div class="detailsNum">
+          <div class="row" v-for="item in numData" :key="item.id">
+            <div class="rowLeft">{{ item.name }}</div>
+            <div class="rowRight">
+              <div class="plan">
+                <div :style="`width:${(item.num / maxNum) * 100}%`"></div>
+              </div>
+            </div>
+            <div class="rowNum">{{ item.num }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 点击搜索出来的页面 -->
+    <Search v-if="searchShow" @close='searchShow=false'/>
+  </div>
+</template>
+
+<script>
+import Search from './Search.vue'
+export default {
+  components: {Search},
+  data() {
+    //这里存放数据
+    return {
+      cutArrows: false,
+      numData: [
+        { id: 1, name: "东宁村", num: 253 },
+        { id: 2, name: "东宁村", num: 353 },
+        { id: 3, name: "东宁村", num: 553 },
+        { id: 4, name: "东宁村", num: 153 },
+        { id: 5, name: "东宁村", num: 252 },
+        { id: 6, name: "东宁村", num: 212 },
+        { id: 7, name: "东宁村", num: 233 },
+        { id: 8, name: "东宁村", num: 298 },
+        { id: 9, name: "东宁村", num: 256 },
+        { id: 10, name: "东宁村", num: 353 },
+        { id: 11, name: "东宁村", num: 643 },
+        { id: 12, name: "马降龙村", num: 243 },
+      ],
+      // 数据最大值
+      maxNum: 0,
+      searchShow:true
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {},
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    let arr = [];
+    this.numData.forEach((v) => {
+      arr.push(v.num);
+    });
+    this.maxNum = arr.reduce((a, b) => (a > b ? a : b));
+    this.maxNum += 100;
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.Home {
+  width: 100vw;
+  height: 100vh;
+  max-width: 500px;
+  margin: 0 auto;
+  position: relative;
+  .map {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: url("../assets/img/homeBg.png");
+  }
+  .top {
+    transition: all 0.3s;
+    color: #fff;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    width: 100%;
+    height: 70px;
+    overflow: hidden;
+    &::before {
+      border-radius: 0 0 20px 20px;
+      content: "";
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 100%;
+      height: calc(100% - 10px);
+      background: rgba(202, 185, 153, 0.9);
+      backdrop-filter: blur(4px);
+      z-index: -2;
+    }
+    .arrows {
+      position: absolute;
+      bottom: 5px;
+      left: 50%;
+      width: 70px;
+      height: 5px;
+      transform: translateX(-50%);
+      &::before {
+        content: "";
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 100%;
+        background: rgba(202, 185, 153, 0.9);
+        backdrop-filter: blur(4px);
+        z-index: -2;
+      }
+      & > div {
+        position: absolute;
+        right: -5px;
+        bottom: 0px;
+        width: 0;
+        height: 0;
+        border-color: transparent rgba(202, 185, 153, 0.9);
+        border-style: solid;
+        border-width: 0px 0px 5px 5px;
+      }
+      .arrowsLeft {
+        right: auto;
+        left: -5px;
+        border-color: rgba(202, 185, 153, 0.9) transparent;
+        border-width: 5px 0px 0px 5px;
+      }
+    }
+    .arrowsImg {
+      position: absolute;
+      bottom: 5px;
+      left: 50%;
+      transform: translateX(-50%);
+      width: 20px;
+    }
+    .tit {
+      width: 100%;
+      height: 55px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      & > h3 {
+        font-size: 20px;
+        font-family: "SYST";
+        margin-right: 20px;
+      }
+      & > img {
+        width: 29px;
+      }
+    }
+    .main {
+      padding-top: 15px;
+      width: calc(100% - 30px);
+      height: calc(100% - 55px);
+      margin: 10px auto 0;
+      border-top: 1px solid #fff;
+      .browse {
+        padding-left: 35px;
+        font-family: "SYST";
+        background: url("../assets/img/gaikuang.png") no-repeat left center;
+        background-size: 29px 29px;
+      }
+      .browse2 {
+        margin-top: 15px;
+        background: url("../assets/img/detail.png") no-repeat left center;
+        background-size: 29px 29px;
+      }
+      .browseNum {
+        display: flex;
+        margin-top: 10px;
+        & > div {
+          padding-left: 35px;
+          width: 50%;
+          text-align: left;
+          & > p {
+            color: #e8e0d1;
+            text-align: left;
+            font-size: 14px;
+            margin-bottom: 5px;
+          }
+          & > span {
+            font-size: 24px;
+          }
+        }
+      }
+      .detailsNum {
+        width: 100%;
+        height: calc(100% - 170px);
+        overflow-y: auto;
+        padding-top: 15px;
+        .row {
+          cursor: pointer;
+          height: 40px;
+          display: flex;
+          .rowLeft {
+            border-right: 1px solid #e8e0d1;
+            text-align: center;
+            line-height: 40px;
+            width: 80px;
+          }
+          .rowRight {
+            width: calc(100% - 170px);
+            position: relative;
+            .plan {
+              position: absolute;
+              left: 0;
+              top: 13px;
+              width: 100%;
+              height: 14px;
+              background-color: rgba(232, 224, 209, 0.8);
+              & > div {
+                position: absolute;
+                left: 0;
+                top: 0;
+                height: 100%;
+                background-color: #fff;
+              }
+            }
+          }
+          .rowNum {
+            padding-left: 5px;
+            width: 90px;
+            line-height: 40px;
+            text-align: center;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+        }
+      }
+    }
+  }
+  .topOpen {
+    height: 93vh;
+    .arrowsImg {
+      transform: translateX(-50%) rotate(180deg);
+    }
+  }
+}
+</style>

+ 175 - 0
webM/src/views/Search.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="search">
+    <div class="top">
+      <!-- 返回按钮 -->
+      <div class="back" @click="$emit('close')"></div>
+      <!-- 搜索按钮 -->
+      <div class="searBtn"></div>
+      <input type="text" v-model="txt" placeholder="请输入关键词..." />
+    </div>
+    <!-- 下面内容 -->
+    <div class="main">
+      <div class="mainTop">
+        <div>村落名称</div>
+        <div>访问量</div>
+      </div>
+      <div class="mainCon">
+        <div class="row" v-for="i in 12" :key="i" @click="$router.push('/stair/1')">
+          <div><span>·</span>卢边村</div>
+          <div>99999</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "search",
+  components: {},
+  data() {
+    //这里存放数据
+    return {
+      txt: "",
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {},
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.search {
+  padding: 18px 12px 0;
+  z-index: 3;
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  &::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(202, 185, 153, 0.9);
+    backdrop-filter: blur(4px);
+    z-index: -2;
+  }
+  .top {
+    position: relative;
+    width: 100%;
+    height: 40px;
+    input {
+      color: #e0bb74;
+      padding: 0 40px;
+      width: 100%;
+      height: 100%;
+      border-radius: 20px;
+      border: none;
+    }
+    /*修改提示文字的颜色*/
+    /deep/input::-webkit-input-placeholder {
+      /* WebKit browsers */
+      color: #bfb094;
+    }
+    /deep/input:-moz-placeholder {
+      /* Mozilla Firefox 4 to 18 */
+      color: #bfb094;
+    }
+    /deep/input::-moz-placeholder {
+      /* Mozilla Firefox 19+ */
+      color: #bfb094;
+    }
+    /deep/input:-ms-input-placeholder {
+      /* Internet Explorer 10+ */
+      color: #bfb094;
+    }
+    .back {
+      position: absolute;
+      top: 6px;
+      left: 10px;
+      width: 29px;
+      height: 29px;
+      background: url("../assets/img/back.png");
+      background-size: 100% 100%;
+    }
+    .searBtn {
+      position: absolute;
+      top: 5px;
+      right: 10px;
+      width: 29px;
+      height: 29px;
+      background: url("../assets/img/search2.png");
+      background-size: 100% 100%;
+    }
+  }
+  .main {
+    padding: 0 10px;
+    border-radius: 10px;
+    margin-top: 10px;
+    background-image: linear-gradient(
+      rgba(255, 255, 255, 1),
+      rgba(255, 255, 255, 0)
+    );
+    width: 100%;
+    height: calc(100% - 60px);
+    .mainTop {
+      display: flex;
+      width: 100%;
+      height: 41px;
+      border-bottom: 1px solid #bfb094;
+      margin-bottom: 20px;
+      & > div {
+        width: 50%;
+        text-align: center;
+        line-height: 40px;
+        font-family: "SYST";
+        color: #5b5b5b;
+        font-size: 14px;
+      }
+    }
+    .mainCon {
+      width: 100%;
+      height: calc(100% - 62px);
+      overflow-y: auto;
+    }
+    .row {
+      display: flex;
+      height: 40px;
+      & > div {
+        width: 50%;
+        text-align: center;
+        color: #5b5b5b;
+        font-size: 14px;
+        line-height: 40px;
+        & > span {
+          font-size: 24px;
+          margin-right: 5px;
+        }
+        &:nth-of-type(1){
+          display: flex;
+          align-items: center;
+          justify-content: center;
+        }
+      }
+    }
+  }
+}
+</style>

Plik diff jest za duży
+ 88 - 0
webM/src/views/stair/component/intro.vue


+ 212 - 0
webM/src/views/stair/index.vue

@@ -0,0 +1,212 @@
+<template>
+  <div class="stair">
+    <!-- 左上浏览量 -->
+    <div class="upleft">
+      <div class="back" @click="$router.push('/')">返回</div>
+      <div class="eye">浏览量:{{ lookNum }}</div>
+    </div>
+    <!-- 右边村名 -->
+    <div class="rightCM">
+      <img class="name" src="../../assets/img/cName/1.png" alt="" />
+      <img class="bs" src="../../assets/img/bs.png" alt="" />
+    </div>
+    <!-- 底部功能 -->
+    <div class="botBtn">
+      <div
+        @click="cutPage(item.id)"
+        class="btnRow"
+        v-for="item in btnData"
+        :key="item.id"
+      >
+        <img
+          :src="
+            require(`@/assets/img/${item.inco}${
+              (item.id === 4) & isShowGood || btnDataAc === item.id
+                ? '_active'
+                : ''
+            }.png`)
+          "
+          alt=""
+        />
+        <!-- 点赞的数字 -->
+        <p v-if="item.id === 4">{{ likeNum }}</p>
+        <transition v-if="item.id === 4" name="likeAddAnimate">
+          <div class="good" v-show="isShowGood">
+            <div class="pic">
+              <img :src="require(`@/assets/img/like_active.png`)" alt="" />
+            </div>
+            <div class="num">+1</div>
+          </div>
+        </transition>
+      </div>
+    </div>
+    <!-- 简介组件 -->
+    <StairIntro v-if="btnDataAc === 1" @close="btnDataAc = null" />
+  </div>
+</template>
+
+<script>
+import StairIntro from "./component/intro.vue";
+import { likeSaveApi, lookSaveApi, getCunNumApi } from "@/utils/api";
+export default {
+  name: "stair",
+  components: { StairIntro },
+  data() {
+    //这里存放数据
+    return {
+      lookNum: 0,
+      likeNum: 0,
+      btnData: [
+        { id: 1, name: "简介", inco: "introduction" },
+        { id: 2, name: "打卡", inco: "daily" },
+        { id: 3, name: "分享", inco: "share" },
+        { id: 4, name: "点赞", inco: "like" },
+        { id: 5, name: "资料", inco: "data" },
+      ],
+      btnDataAc: null,
+      isShowGood: false,
+    };
+  },
+  //监听属性 类似于data概念
+  computed: {},
+  //监控data中的数据变化
+  watch: {},
+  //方法集合
+  methods: {
+    async cutPage(id) {
+      // 点赞
+      if (id === 4) {
+        if (this.isShowGood) return;
+        this.isShowGood = true;
+        await likeSaveApi(Number(this.$route.params.id));
+        setTimeout(() => {
+          this.likeNum++;
+          this.isShowGood = false;
+        }, 1800);
+        return;
+      } else if (id === 5) {
+        this.$router.push(`/info/${this.$route.params.id}`);
+      } else this.btnDataAc = id;
+    },
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  async created() {
+    let id = Number(this.$route.params.id);
+    // 只有从首页进入的才保存浏览量
+    this.$router.beforeEach(async (to, from, next) => {
+      if (from.name === "Home") await lookSaveApi(id);
+      next();
+    });
+
+    let res = await getCunNumApi(id);
+    this.likeNum = res.data.star;
+    this.lookNum = res.data.visit;
+  },
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  mounted() {},
+  beforeCreate() {}, //生命周期 - 创建之前
+  beforeMount() {}, //生命周期 - 挂载之前
+  beforeUpdate() {}, //生命周期 - 更新之前
+  updated() {}, //生命周期 - 更新之后
+  beforeDestroy() {}, //生命周期 - 销毁之前
+  destroyed() {}, //生命周期 - 销毁完成
+  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
+};
+</script>
+<style lang='less' scoped>
+.stair {
+  padding: 10px 0 0 3px;
+  width: 100vw;
+  height: 100vh;
+  background: url("../../assets/img/cBg/1.png");
+  background-size: 100% 100%;
+  .upleft {
+    display: flex;
+    color: #bfb094;
+    .back {
+      padding-right: 10px;
+      padding-left: 30px;
+      border-right: 1px solid #bfb094;
+      background-image: url("../../assets/img/back.png");
+      background-repeat: no-repeat;
+      background-position: 0 -2px;
+      background-size: 29px 29px;
+    }
+    .eye {
+      margin-left: 10px;
+      font-size: 14px;
+    }
+  }
+  .rightCM {
+    position: absolute;
+    top: 17px;
+    right: 14px;
+    .name {
+      width: 37px;
+      margin-right: 8px;
+    }
+    .bs {
+      vertical-align: bottom;
+      width: 27px;
+    }
+  }
+  .botBtn {
+    padding: 0 10px;
+    display: flex;
+    position: absolute;
+    width: 100%;
+    justify-content: space-around;
+    bottom: 20px;
+    left: 0px;
+    .btnRow {
+      position: relative;
+      cursor: pointer;
+      text-align: center;
+      width: 52px;
+      height: 51px;
+      & > img {
+        width: 52px;
+        height: 51px;
+      }
+      & > p {
+        color: #fff;
+        font-size: 14px;
+        text-align: center;
+      }
+    }
+    .likeAddAnimate-enter-active,
+    .likeAddAnimate-leave-active {
+      transition: all 2s ease;
+    }
+    .likeAddAnimate-enter,
+    .likeAddAnimate-leave {
+      transform: translateY(0) scale(0);
+      opacity: 0;
+    }
+    .likeAddAnimate-enter-to,
+    .likeAddAnimate-leave-to {
+      transform: translateY(-50px) scale(1.2);
+      opacity: 1;
+    }
+    .good {
+      position: absolute;
+      top: -10px;
+      right: 0px;
+      display: flex;
+      .pic {
+        width: 35px;
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+      .num {
+        margin-top: 10px;
+        margin-left: 10px;
+        color: #fff;
+        text-shadow: 0 0 10px rgba(0, 0, 0, 1);
+      }
+    }
+  }
+}
+</style>