簡介
使用 Node + vue 對公司的官網進行了一個簡單的移動端的實現。
源碼
https://github.com/wx1993/node-vue-fabaocn
效果
組件
- 輪播圖(使用 vue-awesome-swiper 插件)
- 新聞列表
- 新聞詳情
- 職位列表
- 聯系我們頁面(使用百度地圖api)
技術
Express、Vue、Vue-Router、Vue-Resource、Webpack
Vue
vue 的組件化思想和 React 很像,一個 vue 組件將 html、css 和 js 都寫在一個文件里面,組件管理和維護自己的數據和狀態,方便編寫也便於調試。
Vue-Resource
作為 vue 全家桶的一員,vue-resource 主要用在 HTTP 請求功能上,類似的工具還有 axios,雖然 vue2.0 推薦使用 axios,但是個人還是習慣於用 vue-resource,使用起來也十分簡單,在實例中可以使用以下格式的寫法:
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
關於 vue-resource 的使用可以參考: http://www.jianshu.com/p/3ce2bd36596e
Vue-Router
vue 通過配合 vue-router 來創建單頁應用,其思想是將 vue 組件映射到路由,並將路由掛載到 app 上,在頁面中通過 router-link 和 router-view 來定義頁面路由並切換到不同的組件。
<!-- html --> <router-link to="/home">Home</router-link> // js import Home from './components/home' const routes = [ { path: '/home', component: Home }, ] const router = new VueRouter({ routes }) const app = new Vue({ router }).$mount('#app')
構建
Express + Vue + Webpack
項目結構
經典的 node 項目結構配合手動創建的 src 目錄(用來放置所有的組件、入口和路由文件)。
安裝啟動
// 安裝依賴 npm install // 項目打包 webpack -w // 啟動項目 npm start
幾個問題
因為項目本身並不復雜,所以這里僅針對幾個難點和遇到的坑進行簡單的解釋和分析。
1、接口的封裝和數據的請求
應用相關的接口都在node中進行封裝,具體使用到了 request 模塊的 get 和 post 方法,如下:
// 獲取職位列表 router.post('/getJobs', function (req, res, next) { console.log(req.body.jobId); const jobsUrl = 'http://www.fabao.cn/api/FABAO_WEBSITE/job/getjobinfo?nonce=1494212786000§ionid=' + req.body.jobId +'&pageNumber=1&pageSize=20'; console.log(jobsUrl); request(jobsUrl, function (error, response, body) { if(!error && response.statusCode == '200') { res.send(body) } }) })
請求接口在組件中通過 vue-resource 來實現,如下:
getJoblist () { this.$http.post('/getJobs', { jobId }).then(data => { console.log(data); this.items = data.body.res; }, error => { console.log(error); }) }
2、路由地址變化的的監聽
在項目中的新聞詳情頁面有一個點擊按鈕查看上一篇或下一篇新聞的功能:
這里通過直接在按鈕上定義路由中的新聞 id 的增減的方式來實現,如下:
<router-link :to="{name: 'news', params: {id: data.id - 1}}" replace>{{prevTxt}}</router-link> <router-link :to="{name: 'news', params: {id: data.id + 1}}">{{nextTxt}}</router-link>
但是發現,在點擊了按鈕之后,地址欄中的 url 確實變了,新聞 id 對應的加1或減1,但是頁面內容並沒有發生變化,針對這個問題,可以通過監聽router 來解決,如下:
watch: { // 當路由發生變化時自動請求數據 "$route": "getNewsDetail" }
這樣,在 url 發生變化時,就獲取新的 url 地址,並主動請求一次數據,從而實現了內容的更新。
getNewsDetail 方法如下:
getNewsDetail () { // use vue-resource const curId = this.$route.params.id; this.$http.post('/getNewsDetail', {id: curId }).then(data => { if (data.body.res) { this.prevTxt = '上一篇'; this.nextTxt = '下一篇' this.data = data.body.res[0] }else { if (curId > this.initialId) { // 點擊了下一篇 this.nextTxt = '沒有啦'; this.prevTxt = '上一篇'; }else { // 點擊了上一篇 this.prevTxt = '沒有啦' this.nextTxt = '下一篇' } } }, error => { console.log(error); }) }
3、元素的切換和顯示隱藏
使用 jquery 來實現元素的切換和顯示隱藏十分簡單,只要控制元素的display屬性或者show()/hide()方法或者通過添加和移除類名的方式來實現,但是在 vue 中,因為不便於直接操作 dom 元素,所以在實現這樣的效果的時候需要轉換思路。以"加入我們"頁面的效果為例:
在實現上方標簽的切換和高亮,以及下方職位列表信息的現實隱藏,都涉及到元素屬性和樣式的變化,這里主要是通過動態的類名和 v-show 的方式來實現。
首先,崗位標簽的結構如下:
<div class="job-type"> <span @click="getJoblist(6)" :class="{active: activeId == 6}">急招崗位</span> <span @click="getJoblist(7)" :class="{active: activeId == 7}">日常崗位</span> <span @click="getJoblist(8)" :class="{active: activeId == 8}">校園招聘</span> </div>
在這里,點擊不同的標簽會傳入不同的參數,並請求不同的崗位信息來實現下方列表的更新,同時為每一個標簽都綁定了一個 active 的類名,並通過判斷當前點擊的標簽 id 來控制類名的有無。
getJoblist (jobId) { this.activeId = jobId; this.$http.post('/getJobs', { jobId }).then(data => { console.log(data); this.items = data.body.res; }, error => { console.log(error); }) }
可以看到,在請求職位列表的方法中,首先便通過傳入的 jobId 來設置當前的標簽 id,因為標簽 id 是定義在 data 中的,所以所有的標簽都共享一個 activeId,因此當點擊了標簽時,傳入的 id 便是當前的標簽 id,對應的類名 active 也就為真,同時其他的標簽對應的 active 為假,通過這種方式來實現類名的控制。
同樣,在下方職位列表信息的現實隱藏上也使用了類似的方式,不同的地方在於,在點擊了對應的職位時,不僅需要顯示詳細信息,還需明確當前點擊的是哪一項,因此這里需要用到兩個判斷:
<section class="job-info" @click="showDetail(item.id)"> <h3>{{item.name}}</h3> <div> <address>{{item.company_name}}</address> <span>{{item.type}}</span> <time>{{item.create_date}}</time> </div> </section> <transition name="fade"> <section class="job-detail" v-show="jobId === item.id && ifShow"> <h4>職位描述</h4> <p> <span>崗位職責</span> <pre>{{item.require}}</pre> <span>任職資格</span> <pre>{{item.description}}</pre> </p> </section> </transition>
ifShow 在 組件的 data 中定義,默認為 false,當點擊列表,觸發showDetail(item.id)方法時,傳入當前列表項的id,並賦值給 jobId,同時修改 ifShow,這樣通過兩個布爾值的綜合判斷,可以決定當前點擊項對應的詳情是否顯示。
4、百度地圖的使用
在聯系我們頁面中使用到了百度地圖,同時點擊地址列表,會對地圖信息進行切換和定位,如下:
下面簡單介紹一下在vue組件中百度地圖的使用方法。
首先進入百度地圖API官網(http://lbsyun.baidu.com/index.php?title=jspopular),點擊【獲取密鑰】,然后驗證郵箱,之后根據提示(參照【開發指南】)進行配置,提交后就能獲得一串密鑰,這在引入的api庫需要用到。
在 index.html 中引入百度地圖API
<script src="http://api.map.baidu.com/api?v=2.0&ak=您的密鑰" type="text/javascript"></script>
在組件中使用:
mounted () { this.showMap(121.407585, 31.176521); }, methods: { showMap (x, y, locationId) { this.locationId = locationId; this.showNumber = !this.showNumber; var map = new BMap.Map("container"); // 創建地圖實例 var point = new BMap.Point(x, y); // 創建點坐標 map.centerAndZoom(point, 17); // 初始化地圖,設置中心點坐標和地圖級別 } }
這里定義了一個 showMap() 方法,在里面初始化了地圖並通過傳入的經緯度參數來創建坐標。這部分代碼直接參照百度地圖api的實例即可。在方法中還傳入了一個 locationId,這是因為這里有三個地址,所以要通過這個 id 進行區分。
<div class="location-item"> <div class="location-info clearfix" @click="showMap(121.407585, 31.176521, 1)"> <div class="location-icon"> <img src="/images/home1.png"> </div> <div class="location-content"> <h3>上海總部</h3> <p>徐匯區宜山路1009號18樓</p> </div> </div> <div class="contact-way" v-show="showNumber && locationId == 1"> <p>電話:<a href="tel: 021-54268114">021-54268114</a></p> <p>傳真:<a href="tel: 021-54278114">021-54278114</a></p> </div> </div>
可以看到,在點擊地址列表的時候觸發了showMap()方法,並傳入了當前地址的經緯度和列表項的 id,從而觸發地圖信息的更新。其中經緯度可以在百度地圖中獲取,這里推薦百度地圖生成器,http://api.map.baidu.com/lbsapi/creatmap/index.html,在這里可以通過輸入地名進行定位,並獲取經緯度,同時可以設置級別,添加標注等等,更便捷的是,在設置了相關信息后可以直接獲取代碼,因此使用起來十分方便,如下所示:
百度地圖還提供了很多其他的功能,比如縮放按鈕,地圖標注、實時交通等等,可以根據需要進行配置。這里就不一一介紹了。
關於項目中的其他問題,歡迎大家和我交流:QQ 596291080