1. 程式人生 > >使用vue全家桶製作部落格網站

使用vue全家桶製作部落格網站

前面的話

  筆者在做一個完整的部落格上線專案,包括前臺後臺後端介面和伺服器配置。本文將詳細介紹使用vue全家桶製作的部落格網站

概述

  該專案是基於vue全家桶(vue、vue-router、vuex、vue SSR)開發的一套部落格前臺頁面,主要功能包括首頁顯示、認證系統、文章管理、評論管理和點贊管理

【訪問地址】

  或者可以直接掃描二維碼訪問

【專案介紹】

  該專案的內容以筆者自學前端的過程中寫的600多篇部落格為基礎,對於同樣學習前端的同學可能會有所幫助。許多部落格都有直接可以操作的DEMO,對知識的理解可能會更直觀

  採用移動優先的響應式佈局,移動端、桌面端均可適配;字型大小使用em單位,桌面端的文字相應變大;移動端可使用滑屏操作,桌面端通過游標設定、自定義滾動條、回車確定等,提升互動體驗

  全站採用伺服器端渲染SSR的方式,有利於SEO,減少了首屏渲染時間;使用service worker和manifest實現了PWA方案的離線快取和新增到桌面的功能

  根據HTML標籤內容模型,使用語義化標籤,儘量減少標籤層級,儘量減少無語義的div標籤

  CSS大量使用類選擇器,儘量減少選擇器層級,在vue元件中使用CSS module和postCSS,使用styleLint規範CSS程式碼,按照佈局類屬性、盒模型屬性、文字類屬性、修飾類屬性的順序編寫程式碼,並使用order外掛進行校驗

  使用esLint規範JS程式碼,程式碼風格參照airbnb規範,所有命名採用駝峰寫法,公共元件以Base為字首,事件函式以on為字首,非同步函式以async為字尾,布林值基本以do或is為字首

  沒有引用第三方元件庫,如bootstrap或element元件,而是自己開發了專案中所需的公共元件。在common目錄下,封裝了頭像、全屏、loading、遮罩、搜尋框、聯動選擇等元件,方便開發

  使用配置資料,實現了資料和應用分離,以常量的形式儲存在constants目錄下

  使用了阿里雲的簡訊模組,實現了簡訊驗證功能

  該專案有兩個隱藏彩蛋,一個是搖一搖功能,可以直接搖到後臺頁面,另一個是陀螺儀功能,上下晃動手機時,頭像會進行旋轉

  專案進行了程式碼優化,最終優化評分如下所示

功能演示

  主要功能包括首頁顯示、認證系統、文章管理、評論管理和點贊管理

【首頁顯示】

  首頁包括可拖拽輪播圖、專題推薦、文章推薦和類別推薦

【認證系統】

   認證系統包括使用者註冊、使用者登入、簡訊驗證

  1、使用者處於未登入態時,可以閱讀文章,但不能點贊和評論,否則會彈出登入框

  2、使用者註冊

  3、使用者登入

【文章管理】

  文章管理包括瀏覽推薦文章、按類別篩選、文章搜尋、按目錄檢視

  1、瀏覽推薦文章

  2、文章篩選

  3、文章搜尋

  4、按目錄檢視

【點贊管理】

【評論管理】

  評論管理包括檢視評論、新增評論、修改評論和刪除評論

目錄結構

  src目錄下,包括assets(靜態資源)、common(公共元件)、components(功能元件)、constants(常量配置)、router(路由)、store(vuex)和utils(工具方法)這7個目錄

- assets // 存放靜態資源,主要是圖片
    -imgs
      css.png // CSS文章背景圖
     ...
- common // 存放公共元件
    -SVG // 存放VUE圖示元件
        SVGAdd.vue // "新增到"按鈕
        SVGBack.vue // "返回"按鈕
        ...
    BaseArticle.vue // 文章元件
    BaseAvatar.vue // 頭像元件
    ...
- components // 存放功能元件
    -Post // 文章元件      
      module.js //文章狀態管理    
      Post.vue // 文章顯示元件
      PostContent.vue // 文章目錄元件
      PostList.vue // 文章列表元件
      SearchPost.vue // 搜尋文章元件
      ...
- constants // 存放常量配置
    API.js // 存放API呼叫地址
- router // 存放路由
    index.js 
- store // 存放vuex
    index.js
- utils // 存放工具方法
    async.js // axios方法
    fnVarificate.js // 表單驗證方法
    util.js // 其他工具方法

【公共元件】

  沒有引用第三方元件庫,如bootstrap或element元件,而是自己開發了專案中所需的公共元件

  封裝了文章元件、頭像元件、返回元件、按鈕元件、卡片元件、全屏元件、輸入框元件、loading元件、遮罩元件、搜尋框元件、多行輸入框元件、標題元件、麵包屑元件、按鈕組元件、反色按鈕元件、密碼框元件、包含檢測的輸入框元件和聯動選擇元件

BaseAdd.vue // "新增到"元件
BaseArticle.vue  // 文章元件
BaseAvatar.vue // 頭像元件
BaseBack.vue // 返回元件
BaseButton.vue // 按鈕元件
BaseCard.vue // 卡片元件
BaseFullScreen.vue // 全屏元件
BaseInput.vue  // 輸入框元件
BaseLoading.vue  // loading元件
BaseMask.vue // 遮罩元件
BaseSearchBox.vue  // 搜尋框元件
BaseTextArea.vue // 多行輸入框元件
BaseTitle.vue  // 標題元件
BreadCrumb.vue // 麵包屑元件
ButtonBox.vue  // 按鈕組元件
ButtonInverted.vue // 反色按鈕元件
InputPassword.vue  // 密碼框元件
InputWithTest.vue // 包含檢測的輸入框元件
LinkageSelector.vue // 聯動選擇元件

【功能元件】

  按照功能來設定目錄,如下所示

彈出框(Alert)
類別管理(Category)
評論管理(Comment)
主頁(Home)
點贊管理(Like)
文章管理(Post)
頁面尺寸(Size)
公共頭部(TheHeader) 使用者管理(User)

整體思路

【全屏佈局】

  使用設定高度的全屏佈局方式,主要通過calc來實現

<div
  id="root"
  :class="$style.wrap"
  :style="{height:wrapHeight+'px'}"
>
  ...
  <TheHeader :class="$style.header"/>
  <main :class="$style.main">
    <transition :name="transitionName">
      <router-view :class="$style.router" />
    </transition>
  </main>
</div>
.header {
  height: 40px;
}
.main {
  position: relative;
  height: calc(100% - 40px);
  overflow: auto;
}

【層級管理】

  專案的層級z-index,只使用0-3

  全屏的彈出框優化級最高,設定為3;側邊欄設定為2;頁面元素預設為0,如有需要,要設定為1

【全域性彈出層】

  在入口檔案App.vue中設定全域性的彈出層和loading,所有元件都可以共用

// App.vue
<template>
  <div
    id="root"
    :class="$style.wrap"
    :style="{height:wrapHeight+'px'}"
  >
    <AlertWithLoading v-show="doShowLoading" />
    <AlertWithText
      v-show="alertText !== ''"
      :text="alertText"
      :onClick="() => {$store.commit(HIDE_ALERTTEXT)}"
    />
    <TheHeader :class="$style.header"/>
    <main :class="$style.main">
      <transition :name="transitionName">
        <router-view :class="$style.router" />
      </transition>
    </main>
  </div>
</template>

【路由管理】

  vue-router使用靜態路由表的形式對路由進行管理,雖然沒有react-router-dom靈活,但方便尋找,一目瞭然

  按路由設定按需載入元件,並設定滾動行為

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
export default function createRouter() {
  return new Router({
    mode: 'history',
    routes: [
      {
        path: '/',
        component: () => import(/* webpackChunkName:'home' */ '@/components/Home/Home'),
        name: 'home',
        meta: { index: 0 }
      },
      {
        path: '/posts',
        component: () => import(/* webpackChunkName:'post' */ '@/components/Post/PostList'),
        name: 'postlist'
      },
      {
        path: '/posts/search',
        component: () => import(/* webpackChunkName:'post' */ '@/components/Post/SearchPost'),
        name: 'searchpost'
      },
      {
        path: '/posts/:postid',
        component: () => import(/* webpackChunkName:'post' */ '@/components/Post/Post'),
        name: 'post',
        children: [
          {
            path: 'comments',
            name: 'commentlist',
            component: () => import(/* webpackChunkName:'comment' */ '@/components/Comment/CommentList'),
            children: [
              {
                path: 'add',
                name: 'addcomment',
                component: () => import(/* webpackChunkName:'comment' */ '@/components/Comment/AddComment')
              },
              {
                path: ':commentid/update',
                name: 'updatecomment',
                component: () => import(/* webpackChunkName:'comment' */ '@/components/Comment/UpdateComment')
              },
              {
                path: ':commentid/delete',
                name: 'deletecomment',
                component: () => import(/* webpackChunkName:'comment' */ '@/components/Comment/DeleteComment')
              }
            ]
          }
        ]
      },
      {
        path: '/categories',
        component: () => import(/* webpackChunkName:'category' */ '@/components/Category/CategoryList'),
        name: 'categorylist'
      },
      {
        path: '/categories/:number',
        component: () => import(/* webpackChunkName:'category' */ '@/components/Category/Category'),
        name: 'category'
      },
      {
        path: '/topics/:number',
        component: () => import(/* webpackChunkName:'category' */ '@/components/Category/CategoryTopic'),
        name: 'topic'
      },
      // 註冊
      {
        path: '/signup',
        component: () => import(/* webpackChunkName:'user' */ '@/components/User/AuthSignup'),
        name: 'signup'
      },
      // 按手機號登入
      {
        path: '/signin_by_phonenumber',
        component: () => import(/* webpackChunkName:'user' */ '@/components/User/AuthSigninByPhoneNumber'),
        name: 'signin_by_phonenumber'
      },
      // 按使用者名稱登入
      {
        path: '/signin_by_username',
        component: () => import(/* webpackChunkName:'user' */ '@/components/User/AuthSigninByUsername'),
        name: 'signin_by_username'
      },
      // 使用者頁面
      {
        path: '/users/:userid',
        component: () => import(/* webpackChunkName:'user' */ '@/components/User/UserDesk'),
        name: 'user'
      }
    ],
    scrollBehavior(to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition
      }
      return { x: 0, y: 0 }
    }
  })
}

【狀態管理】

  每個元件的狀態管理命名為module.js,儲存在當前元件目錄下

import Vue from 'vue'
import Vuex from 'vuex'
import auth from '@/components/User/module'
import alert from '@/components/Alert/module'
import post from '@/components/Post/module'
import category from '@/components/Category/module'
import like from '@/components/Like/module'
import size from '@/components/Size/module'
import comment from '@/components/Comment/module'

Vue.use(Vuex)
export default function createStore() {
  return new Vuex.Store({
    modules: {
      auth,
      alert,
      post,
      category,
      like,
      size,
      comment
    }
  })
}

  每個元件的狀態包括state、getters、actions和mutations欄位,以Category元件為例

import { BASE_CATEGORY_URL } from '@/constants/API'
import { getNumberWithoutPostPositiveZero, getCategoryNumbers } from '@/utils/util'

export const LOAD_CATEGORIES = 'LOAD_CATEGORIES'
export const LOAD_CATEGORIES_ASYNC = 'LOAD_CATEGORIES_ASYNC'
const category = {
  state: {
    docs: []
  },
  getters: {
    categoryCount: state => state.docs.length,
    getCategoriesByNumber: state => state.docs.reduce((obj, t) => {
      obj[t.number] = t
      return obj
    }, {}),
    getCategoryByNumber: state => number => state.docs.find(doc => doc.number === number),
    getPosterityCategories: (state, getters) => number => {
      const reg = new RegExp(`^${getNumberWithoutPostPositiveZero(number)}`)
      return state.docs.filter(doc => {
        doc.titleDatas = getCategoryNumbers(doc.number).map(t => getters.getCategoriesByNumber[t].name)
        return String(doc.number).match(reg) && (doc.posts.length)
      })
    },
    getChildrenCategoryies: state => number => {
      const reference = String(getNumberWithoutPostPositiveZero(number))
      const len = reference.length
      const regExp = new RegExp(`^${reference}(0[1-9]|[1-9][0-9])(0){${8 - len}}`)
      return state.docs.filter(doc => String(doc.number).match(regExp))
    },
    getCategoryRootDatas: state => state.docs.filter(doc => Number(String(doc.number).slice(2)) === 0),
    getRecommendedCategories: state => state.docs.filter(t => t.recommend).sort((a, b) => a.index - b.index)
  },
  actions: {
    /* 獲取全部類別資訊 */
    [LOAD_CATEGORIES_ASYNC]({ commit }) {
      return new Promise((resolve, reject) => {
        this._vm.$axios({
          commit,
          url: BASE_CATEGORY_URL,
          doHideAlert: true,
          success(result) {
            // 儲存類別
            commit(LOAD_CATEGORIES, result.docs)
            // 向前端通知操作成功
            resolve(result.docs)
          },
          fail(err) {
            // 向前端通知操作失敗
            reject(err)
          }
        })
      })
    }
  },
  mutations: {
    /* 儲存類別資訊 */
    [LOAD_CATEGORIES](state, payload) {
      state.docs = payload
    }
  }
}
export default category

【資料傳遞】

  元件間的資料傳遞方式一般有三種,一種是使用vue中的props和自定義事件,另一種是使用路由的params屬性,還有一種是通過vuex

  1、props和自定義事件

// BaseInput
<template>
  <input
    :class="$style.input"
    :value="value"
    autocomplete="off"
    autocapitalize="off"
    @input="$emit('input', $event.target.value)"
  >
</template>
<script>
export default {
  props: {
    value: { type: String, default: '' }
  }
}
</script>

// InputPassword
<input
  :class="$style.input"
  :placeholder="placeholder"
  :value="value"
  autocomplete="off"
  autocapitalize="off"
  type="password"
  @input="$emit('input',$event.target.value)"
>

  2、路由的params屬性

// Post.vue
 <BaseBack @click.native="$router.push($route.params.parentPath || '/')">返回</BaseBack>

//AuthSign.vue
<template>
    <router-link
        :active-class="$style.active"
        :to="{ name: 'signin', params: { parentPath } }"
    >登&nbsp;錄</router-link>
</template>
<script>
export default {
  computed: {
    parentPath() {
      const temp = this.$route.params.parentPath
      if (temp) {
        return temp
      }
      return ''
    }
  }
}
</script>

  3、使用vuex

// Category.vue
<template>
  <article v-if="category" :class="$style.box">
    <BaseBack @click.native="$router.push('/categories')">類別列表</BaseBack>
    <BaseTitle>{{ category.name }}知識體系</BaseTitle>
    ...
  </article>
</template>
<script>
export default {
  computed: {
    category() {
      return this.$store.getters.getCategoryByNumber(Number(this.paramsNumber))
    }
    ...
  }
}
</script>

專案優化

【離線快取】

  通過service worker實現離線快取效果

const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

plugins: [
  new SWPrecacheWebpackPlugin({
    dontCacheBustUrlsMatching: /\.\w{8}\./,
    filename: 'service-worker.js',
    logger(message) {
      if (message.indexOf('Total precache size is') === 0) {
        return;
      }
      if (message.indexOf('Skipping static resource') === 0) {
        return;
      }
      console.log(message);
    },
    navigateFallback: 'https://www.xiaohuochai.cc',
    minify: true,
    navigateFallbackWhitelist: [/^(?!\/__).*/],
    dontCacheBustUrlsMatching: /./,
    staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/],
    runtimeCaching: [{
        urlPattern: '/',
        handler: 'networkFirst'
      },
      {
        urlPattern: /\/(posts|categories|users|likes|comments)/,
        handler: 'networkFirst'
      }
    ]
  })
]

【新增到桌面】

  andriod下,通過設定manifest.json檔案新增到桌面,而IOS則需要設定meta標籤

<meta name="theme-color" content="#fff"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="前端小站">
<link rel="apple-touch-icon" href="/logo/logo_256.png">
<link rel="shortcut icon" href="/logo/favicon.ico">
<link rel="manifest" href="/manifest.json" />

// manifest.json
{
  "name": "小火柴的前端小站",
  "short_name": "前端小站",
  "start_url": "/",
  "display": "standalone",
  "description": "",
  "theme_color": "#fff",
  "background_color": "#d8d8d8",
  "icons": [{
      "src": "./logo/logo_32.png",
      "sizes": "32x32",
      "type": "image/png"
    },
    {
      "src": "./logo/logo_48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "./logo/logo_96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "./logo/logo_144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "./logo/logo_192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./logo/logo_256.png",
      "sizes": "256x256",
      "type": "image/png"
    }
  ]
}

【子頁面重新整理】

  子頁面重新整理時,可能會出現得不到從父級傳遞過來的資料的情況,筆者的處理是跳轉到父級頁面

mounted() {
  if (!this.comment && this.operate === 'update') {
    this.$router.push(`/posts/${this.postId}/comments`)
  } else {
    this.setTextAreaValue()
  }
}

【promise】

  為actions新增Promise,方便狀態改變後的處理

[LOAD_COMMENTS_ASYNC]({ commit }, payload) {
  return new Promise((resolve, reject) => {
    this._vm.$axios({
      commit,
      data: payload,
      url: BASE_COMMENT_URL,
      doHideAlert: true,
      success(result) {
        // 儲存類別
        commit(LOAD_COMMENTS, result.docs)
        // 向前端通知操作成功
        resolve(result.docs)
      },
      fail(err) {
        // 向前端通知操作失敗
        reject(err)
      }
    })
  })
}

【元件共用】

  由於編輯和新建元件用到的元素是一樣的,只不過,新建元件時內容為空,編輯元件時需要新增內容,這時就可以複用元件

// AddComment.vue
<CommentForm operate="add" />

//UpdateComment.vue
<CommentForm operate="update" />

【清理環境】

  如果使用addEventListener綁定了事件處理函式,在元件銷燬的時候,要及時清理環境

mounted() {
  window.addEventListener('devicemotion', throttle(this.testShake))
}
beforeDestroy() {
  window.removeEventListener('devicemotion', throttle(this.testShake))
}

【應用和資料分離】

  使用配置資料,實現資料和應用分離,配置資料主要是API呼叫地址,以常量的形式儲存在constants目錄下

// API.js
let API_HOSTNAME
if (process.env.NODE_ENV === 'production') {
  API_HOSTNAME = 'https://api.xiaohuochai.cc'
} else {
  API_HOSTNAME = '/api'
}
export const SIGNUP_URL = `${API_HOSTNAME}/auth/signup`
export const SIGNIN_BYUSERNAME_URL = `${API_HOSTNAME}/auth/signin_by_username`
export const SIGNIN_BYPHONENUMBER_URL = `${API_HOSTNAME}/auth/signin_by_phonenumber`
export const VERIFICATE_URL = `${API_HOSTNAME}/auth/verificate`

export const BASE_USER_URL = `${API_HOSTNAME}/users`
export const BASE_POST_URL = `${API_HOSTNAME}/posts`
export const BASE_TOPIC_URL = `${API_HOSTNAME}/topics`
export const BASE_CATEGORY_URL = `${API_HOSTNAME}/categories`
export const BASE_LIKE_URL = `${API_HOSTNAME}/likes`
export const BASE_COMMENT_URL = `${API_HOSTNAME}/comments`

export const ADMIN_URL = 'https://admin.xiaohuochai.cc'

【函式節流】

  為觸發頻率較高的函式使用函式節流

/**
 * 函式節流
 * @param {fn} function test(){}
 * @return {fn} function test(){}
 */
export const throttle = (fn, wait = 100) => function func(...args) {
  if (fn.timer) return
  fn.timer = setTimeout(() => {
    fn.apply(this, args)
    fn.timer = null
  }, wait)
}

【DNS預解析】

  DNS預解析通過設定meta標籤實現

<link rel="dns-prefetch" href="//api.xiaohuochai.cc" />
<link rel="dns-prefetch" href="//static.xiaohuochai.site" />
<link rel="dns-prefetch" href="//demo.xiaohuochai.site" />
<link rel="dns-prefetch" href="//pic.xiaohuochai.site" />

【圖片懶載入和webp】

  通過vue-lazyload外掛實現圖片懶載入和andriod系統下圖片轉換成webp格式


            
           

相關推薦

使用vue全家製作部落網站

前面的話   筆者在做一個完整的部落格上線專案,包括前臺、後臺、後端介面和伺服器配置。本文將詳細介紹使用vue全家桶製作的部落格網站 概述   該專案是基於vue全家桶(vue、vue-router、vuex、vue SSR)開發的一套部落格前臺頁面,主要功能包括首頁顯示、認證系統、文章管理、評論管

使用react全家製作部落後臺管理系統

前面的話   筆者在做一個完整的部落格上線專案,包括前臺、後臺、後端介面和伺服器配置。本文將詳細介紹使用react全家桶製作的部落格後臺管理系統 概述   該專案是基於react全家桶(React、React-router-dom、redux、styled-components)開發的一套部落格後臺

【WEB】vue搭建自己的部落網站並部署到伺服器

技術框架和基本庫: 1.前端:vue-cli腳手架,vue-router管理路由,axios前後端互動。 2.伺服器端:使用node語言開發,express作為開發框架,提供api藉口給前端ajax呼叫。路由和render交給vue解決。同時以RESTful

基於 Vue 全家製作的移動端音樂 WebApp

專案演示地址: https://bxm0927.github.io/vue-music-webapp/dist/ (在 GitHub Pages 中,通過 jsonp 請求的資料會被正常渲染,而由於無 node 服務,通過 axios 請求的資料不會被正常

從零開始系列之vue全家(4)帶新手小白一起搭建第一個個人網站項目

轉載 個人網站 rfi red nbsp oot ott osx 全部 未經允許,嚴禁轉載,全文由blackchaos提供。 在安裝好了前面大部分需要的插件,我們開始進行第一個個人項目。結合vue+vuex+vue-cli+vue-router+webpack使用。

利用Word和Github製作個人部落網站(二)

前言 在前面第一篇已經介紹了怎樣建立一個用Word製作的部落格首頁。連結 這篇進一步完善我們的部落格體系,閱讀完此篇基本就可以了。更多奇淫技巧,不定期分享。 一、建立部落格目錄網頁 1,在資料夾中建立一個word命名為directory.docx,然後開啟,製作目

Vue + TypeScript + Element 搭建簡潔時尚的部落網站及踩坑記

前言 本文講解如何在 Vue 專案中使用 TypeScript 來搭建並開發專案,並在此過程中踩過的坑 。 TypeScript 具有型別系統,且是 JavaScript 的超集,TypeScript 在 2018年 勢頭迅猛,可謂遍地開花。 Vue3.0 將使用 TS 重寫,重寫後的 Vue3.0 將更

Vue 全家 + Express 實現的博客(後端API全部自己手寫)

vue express node mysql vuex 為什麽學習並使用Vue1.發展趨勢最近這幾年的前端圈子,由於戲臺一般精彩紛呈,從 MVC 到 MVVM,你剛唱罷我登場。 backbone,AngularJS 已成昨日黃花,reactjs 如日中天,同時另一更輕量的 vue 發展勢頭

搭建vue全家

靜態頁 light -- vue ack sas nbsp sass log 1、直接利用vue-cli腳手架快速搭建 (1)全局安裝vue-cli npm install -g vue-cli (2)創建項目 vue init webpack-simple my-

從零開始系列之vue全家(3)安裝使用vuex

info 獲取 clas from 顯示 共享 安裝 default 重要 什麽是vuex? vuex:Vue提供的狀態管理工具,用於同一管理我們項目中各種數據的交互和重用,存儲我們需要用到數據對象。 即data中屬性同時有一個或幾個組件同時使用,就是data中共用的屬性。

已配置好的vue全家項目router,vuex,api,axios,vue-ls,async

vuejsgithub 地址: https://github.com/liangfengbo/vue-cli-project 點擊進入 vue-cli-project 已構建配置好的vuejs全家桶項目,統一管理後端接口 | 獲取數據 | 請求數據,已包含vue-router,vuex,api,axios.

項目- Vue全家實戰去哪網App

.org 編譯 script image 項目上線 str 用戶 設計 fastclick 最近在學習Vue,花了幾天時間跟著做了這個項目,算是對學習Vue入門的一個總結,歡迎同學們star 去哪網APP ?? 項目演示地址:http://118.25.39.84 基於

從0開始使用python flask編寫部落網站(2)

好了上一篇文章中搭建好了完整的框架,以及可以訪問一個“hello world”頁面了。現在繼續完善我們的部落格程式。 1.如法炮製,繼續完善error和admin的路由。 首先寫把404和500的網頁寫好放到templates/errors中。然後在error的資料夾中新建handlers.py 檔案,在

搭建一個自己的部落網站——前端(一

前臺頁面搭建 前臺頁面 前臺頁面 前臺的頁面,主要使用bootstrap和jq。在靜態頁面開發中使用了gulp。gulp功能多多嘛,雖然我用的sublime,很多功能不用gulp也能做到,不過還是有很多東西用

(七)基於SSM+Redis+Nginx+FastDFS的部落網站

 本篇介紹FastDFS,無需整合spring即可使用,前端上傳圖片到控制層,控制層呼叫fastDFS工具類實現上傳,上傳成功返回檔案地址到前端。 配置檔案為fast_client.conf,fastDFS要求使用的檔名和屬性名,要一致。 tracker_server =

(一)基於SSM+Redis+Nginx+FastDFS的部落網站

  這篇部落格介紹的是自我用了SSM(spring、SpringMVC和Mybatis)後,基於一個前端模板做的一個網站。由於自己比較喜歡做分散式架構的網站,所以就基於自己現有所學的技術實現某些功能,當然肯定有很多可以改進的地方。基本框架用的是SSM,資料庫用的是MYSQL,快取用

(三)基於SSM+Redis+Nginx+FastDFS的部落網站

上一篇主要介紹了SSM整合以及測試。 這一篇主要介紹登入模組,登入模組用到了過濾器,配置過濾器時需要在web.xml裡面進行配置,相關配置已經在第二篇的web.xml有註明。  本篇涉及的類有:控制層的LoginController、過濾器CheckLoginFilte

(五)基於SSM+Redis+Nginx+FastDFS的部落網站

 上一篇介紹了redis的相關使用,這一篇介紹本專案使用的圖片儲存時用到的技術——FastDFS。專案使用時參考的是傳智播客裡的FastDFS的使用教程。由於只有文件沒有地址,所以就直接黏貼過來,若有版權問題請告知,謝謝。 1 課程目標

(六)基於SSM+Redis+Nginx+FastDFS的部落網站

上一篇介紹了FastDFS。 這一篇開始介紹redis和FastDFS在本專案中是如何使用的。首先介紹redis Jedis工具類介面 package com.tdrip.dao; public interface JedisClient { //redis get方法 :

(四)基於SSM+Redis+Nginx+FastDFS的部落網站

 Redis是用C語言開發的一個開源的高效能鍵值對(key-value)資料庫。它通過提供多種鍵值資料型別來適應不同場景下的儲存需求,目前為止Redis支援的鍵值資料型別如字串型別、雜湊型別、列表型別、集合型別、有序集合型別。 菜鳥教程裡有基本的使用命令:點選開啟連結