vuejs2 + wp-rest-api開發web app

以前我寫了一篇《利用Cordova,jqurey與wp-rest-api製做一個屬於本身博客的移動APP》,使用的是jQuery mobile的方式進行web app的開發,今天我就說一下使用vuejs 與 wp-reset-api開發一個web app的方法。
先看看作好之後的效果吧:
vue-egtch.gifcss

1、首先安裝nodejs

安裝方法請自行去官方網站查看html

2、安裝vue-cli

一、直接打開nodejs的命令窗口輸入如下命令:
npm install -g vue-cli //全局安裝vue-cli
vue init webpack egtch //生成項目名爲egtch的模板,這裏的項目名egtch隨你本身寫
輸入這個目錄後會出現以下所示
20170315223131.pngvue

? Project name 本身填寫一個項目名稱 ? Project description (A Vue.js project)
這裏是項目描述,隨便填寫 ? Author 這個是開發者信息,會自動獲取,也能夠本身設置html5

Runtime + Compiler: recommended for most users Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are
ONLY allowed in .vue files - render functions are required elsewherenode

看到這個,直接回車跳過 ? Install vue-router? (Y/n)
//這裏選擇y,安裝vue-router(路由)功能,以便咱們進行相應的開發。 ? Use ESLint to lint your
code? (Y/n) //若是你想要使用eslint提示,那麼你選擇y,不知道這個是什麼東西的同窗,直接選擇n吧。 ? Setup
unit tests with Karma + Mocha? //這兩個是js測試框架,選擇n ? Setup e2e tests with
Nightwatch? (Y/n) //這個也直接選擇nlinux

二、以上步驟都完成後,即將看到以下的提醒哦webpack

vue-cli · Generated "egtch". To get started: cd egtch npm install npm
run dev 三、而後咱們在執行如下命令 cd egtch //進入項目所在目錄 npm install //初始化安裝依賴
這樣咱們在回來看咱們的目錄結構,將在egtch目錄下生成以下目錄結構 vue-cli項目目錄git

npm run d

npm run dev //在瀏覽器中運行當前的vue項目
這樣就能夠看到vue-cli默認的一個頁面展示在咱們眼前了,以下圖:
vue-cli演示頁面
vue-cli演示頁面github

四、在咱們開發中會用到vue-resource與stylus
咱們能夠經過命令 npm install vue-resource -save來進行下載vue-resource安裝
npm install stylus -save
固然也能夠修改egtch根目錄下的packge.json文件中的代碼後,在執行npm install,修改如圖
packge.json修改
packge.json修改web

而且修改

"devDependencies": {
…………
"css-loader": "^0.26.1", //在這個下面添加stylus
//必需要添加2個關於stylus的依賴庫
"stylus-loader": "^2.5.0",
"stylus": "0.52.4",
…………
}

3、wp-rest-api v2使用

(官方地址http://v2.wp-api.org/
好比,若是想要獲取wordpress中最新的文章,你能夠直接在瀏覽器中輸入: http://www.egtch.com/wp-json/...,你們能夠經過本站的相關api去訪問 若是想獲取指定的文章(按文章ID),能夠輸入: http://www.egtch.com/wp-json/... 獲取第一頁的文章 http://www.egtch.com/wp-json/... 第二頁page=2以此類推 更多關於wp-rest-api用法,請參考官方文檔api

4、進入vue開發

一、打開根目錄下的index.html,修改title,而且在head中增長手機端設備支持代碼
而且導入reset.css(自行到網上尋找適合本身的reset.css),而且將其放在static目錄中
二、在main.js中引入vue-resource

import VueResource from 'vue-resource'
Vue.use(VueResource)

三、在src/assets下新建一個css目錄,並在目錄下創建一個public.styl文件,其代碼以下
注意:使用stylus中,縮進必須正確,不然就會出現嚴重的問題

font-rem($num)
  font-size ($num/16)rem
bg-change($color)
  background $color
body
  background #CCC
  font-family "Microsoft Yahei","Helvetica Neue",Helvetica,Arial,sans-serif
  font-weight lighter
  height 100%
h1,h2,h3,h4,h5,h6
  font-weight 400
  color black
  border-left 2px #CCC solid
  margin 10px 0
  padding 0 0 0 8px
  line-height 1
  font-rem(18)
//手機端真正實現1px的線
.line
  width 90%
  margin 0 auto
  flex 1
  position relative
  top -6px
  border-bottom 1px solid #F2F2F2
.line-k
  width 100%
  margin 10px auto 0 auto
  flex 1
  position relative
  top -6px
  border-bottom 1px solid #F2F2F2
.codecolorer-container
  width 90%
  background #f2f2f2
  margin 0 auto
  color dimgrey
  overflow auto
  border 1px #CCC solid
  padding 3%
  font-rem(14)
.wp-caption
  text-align center

四、修改src目錄下的App.vue以下

<template>
  <div id="app">
    <top></top>
    <transition :name="$router.app.pageTransition">
        <router-view></router-view>
    </transition>
    <bottom></bottom>
  </div>
</template>

<script>
import Top from './components/Top.vue'
import Bottom from './components/Bottom.vue'
export default {
  components:{
    'top':Top,
    'bottom':Bottom
  }
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import "./assets/css/public.styl"
@import "./assets/css/font-awesome.min.css"
#app
  width 100%
  height 100%
  display table
  overflow auto
  /*right start*/
  .slide-right-enter-active
    transition all .4s ease
  .slide-right-enter
    opacity 0.9;
    transform translate3d(100%, 0, 0)
  .slide-right-leave
    transform translate3d(0, 0, 0)
  .slide-right-leave-active
    transition all .4s ease
    opacity .5
    transform translate3d(-20%, 0, 0)
  /*right end*/
  /*left start*/
  .slide-left-enter-active
    transition all .4s ease;
    transform translate3d(0%, 0, 0);
    z-index 1998
  .slide-left-enter
    opacity .5
    transform translate3d(-20%, 0, 0)
    z-index 1998
  .slide-left-leave
    transform translate3d(0, 0, 0)
  .slide-left-leave-active
    transition all .4s ease
    opacity 0.9
    transform translate3d(100%, 0, 0)
  /*left end*/
  .slide-fade-enter-active
    transition all .4s ease
  .slide-fade-leave-active
    transition all .4s ease
  .slide-fade-enter,
  .slide-fade-leave-active
    opacity 0
  .slide-fade-enter
    padding-top 80%
  .slide-fade-leave-active
    padding-top -100%
</style>

五、咱們在src目錄下的commponents目錄下創建一個Posts.vue來獲取,代碼以下:

<template>
  <div class="po">
    <div class="posts">
        <div class="box" v-for="(item, index) in posts">
          <div class="post">
            <router-link :to="{path:'/article',query: {id:posts[index].id}}">{{posts[index].title.rendered}}</router-link>
            <div class="line-k"></div>
            <div class="posts-img" v-html="getFirstImg(posts[index].content.rendered)"></div>
            <div class="description" v-html="replaceDS(posts[index].excerpt.rendered)"></div>
          </div>
        </div>
          <a id="pre" @click="pre"><i class="fa fa-angle-left" aria-hidden="true"></i>PREVIOUS</a>
          <a id="next" @click="next">NEXT<i class="fa fa-angle-right" aria-hidden="true"></i></a>
    </div>
  </div>
</template>
<style lang="stylus" rel="stylesheet/stylus">
  @import "../assets/css/public.styl"
  @import "../assets/css/font-awesome.min.css"
.po
  background #ffffff
  width 100%
  .posts
    width 100%
    height 100%
    overflow auto
    margin 40px auto 68px auto
    & a
      color darkcyan
      padding 5px
      border-radius 2px
      &#pre
        float left
        font-rem(18)
        padding 5px 10px 10px 10px
        line-height 32px
        & i
          font-rem(28)
          margin-right 10px
          float left
      &#next
        float right
        font-rem(18)
        padding 5px 10px 10px 10px
        line-height 32px
        & i
          font-rem(28)
          margin-left 10px
          float right
    .box
      width 100%
      margin 10px auto
      background #ffffff
      padding 10px 0
      line-height 1.5
      border-bottom 6px solid #F2F2F2
      .post
        width 96%
        margin 0 auto
        & a
          color darkcyan
          background none
          font-rem(18)
          margin 0 auto 5px auto
          padding 5px 0
        .posts-img
          width 90%
          margin 0 auto
          padding 5px 0 0 0
          & > img
            max-width 100%
            border 2px solid #CCC
            border-radius 5px
        .description
          font-rem(16)
          padding-top 5px
          color dimgrey
</style>
<script>
    export default{
      name:'iposts',
      data() {
        return{
          apiUrl:'http://www.egtch.com/wp-json/wp/v2/posts',
          posts:{},
          page: 1,
          show: false
        }
      },
      created(){
        this.getPosts(this.page)
      },
      watch: {
        // 若是路由有變化,會再次執行該方法
        'page': 'getPosts'
      },
      methods:{
        getPosts(p){
              if(p<1){
                  p = 1
              }
              this.$http.get(this.apiUrl+'?page='+p).then(response => {
                // get body data
                response = response.body
                if(response.length > 0){
                  this.posts = response
                  document.getElementById('next').style.display='block';
                }
                if(response.length < 10){
                  document.getElementById('next').style.display='none';
                }

                //alert(response);
                //console.log(this.posts);
                //alert(this.page)
              })
          },
        //獲取class對象
        $class(domclass){
          var odiv = document.getElementsByTagName("*");
          var aResult = []; //定義一個空數組,用來存放與目標className相同的元素
          for(var i = 0; i<odiv.length; i++)
          {//這個是遍歷頁面中全部元素而後拿他們的class進行對比。若是和咱們傳進來的domclass這個參數同樣就把他放進數組 aResult中。
            if(odiv[i].className == domclass)
            {
              aResult.push(oDiv[i]);   //獲取到的元素推動數組中
            }
            return aResult;   //返回這個放進了domclass元素的數組
          }
        },
          getFirstImg(strs){
              var content = strs;
              var str = /<img [^>]*src=['"]([^'"]+)([^>]*>)/gi;
              var src = str.exec(content);
              if(src===null || src===undefined || src===[]) {
                src='';
              }else {
                src = src[0];
                src = src.replace(/ height="\d+"/g, '');
                src = src.replace(/ width="\d+"/g, '');
              }
              /*document.getElementById('imgs').src = src;
              console.log(src);
              alert(src)*/
              return src;

          },
          replaceDS(str){
            /*[&hellip;]*/
            var dc = str.replace(/\[&hellip;\]/g, '');
            return dc;
          },
          next(){
            scrollTo(0,0);
            this.page++;
            this.showClose();
          },
          pre(){
            scrollTo(0,0);
            this.page--;
          },
          showClose(){
            this.show = !this.show;
          }
      }
    }

</script>

六、創建一個Article.vue獲取文章內容

<template>
  <div class="artic">
    <div class="article" v-if="article">
      <div class="box">
        <div class="title">{{article.title.rendered}}</div>
        <div class="line-k"></div>
        <div class="content" v-html="replaceImgHW(article.content.rendered)"></div>
      </div>
    </div>
  </div>
</template>
<style lang="stylus" rel="stylesheet/stylus">
  @import "../assets/css/public.styl"
.artic
  background #ffffff
  width 100%
  .article
    width 100%
    height 100%
    overflow auto
    margin 40px auto 68px auto
    display block
    background #ffffff
    .box
      width 100%
      margin 0 auto
      line-height 2.5
      .title
        font-weight 600
        text-align center
        margin 0 auto 10px auto
        font-rem(20)
        background darkcyan
        color #f2f2f2
      .content
        font-rem(16)
        word-break break-all
        color dimgrey
        padding 8px
        & img
          max-width 90%
          border 1px #ccc solid
          border-radius 5px
          margin-left 5%
        .wp-caption
          width 100%
          text-align center
          & img
            max-width 90%
            border 1px #ccc solid
            border-radius 5px
</style>
<script>
  export default{
    name:'iarticle',
    data() {
      return{
        apiUrl:'http://www.egtch.com/wp-json/wp/v2/posts/',
        article:{},
        id: this.$route.query.id
      }
    },
    created(){
      this.getArticle();
    },
    watch: {
      // 若是路由有變化,會再次執行該方法
      'this.id': 'getArticle'
    },
    methods:{
      getArticle(){
        // GET /someUrl
        this.$http.get(this.apiUrl+this.id).then(response => {
          // get body data
          response = response.body
          this.article = response
          //alert(response);
          //console.log(this.article);
          //alert(this.id)
        })
      },
      replaceImgHW(strs){
        var st1 = strs.replace(/ height="\d+"/g,'');
        var st2 = st1.replace(/ width="\d+"/g,'');
        var st3 = st2.replace(/width: \d+px/g,'');
        var st4 = st3.replace(/ style/g,'');
        var st5 = st4.replace(/=""/g,'');
        var st = st5.replace(/href=/g,'target="_blank" href=');
        return st;
      }
    }
  }
</script>

七、再新建一個Categories.vue讀取分類

<template>
  <div class="cats">
    <div class="categories" v-if="categories">
      <div v-for="(item, index) in categories">
        <div class="categories-item" v-if="categories[index].parent != 0">
          <router-link :to="{path:'/postcat',query: {id:categories[index].id}}"><span v-html="icoIn[index]"></span><span>{{categories[index].name}}</span><span class="cat">{{categories[index].slug}}</span><i class="fa fa-angle-right" aria-hidden="true"></i></router-link>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
/*import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)*/
export default {
  data() {
    return{
      categories:{},
      catUrl:'http://www.egtch.com/wp-json/wp/v2/categories?per_page=15',
      icoIn:{}
    }
  },
  created(){
      this.getCat()
      this.icoIn = [
          '<i class="fa fa-html5" aria-hidden="true"></i>',
          '<i class="fa fa-coffee" aria-hidden="true"></i>',
          '<i class="fa fa-code" aria-hidden="true"></i>',
          '<i class="fa fa-file-code-o" aria-hidden="true"></i>',
          '<i class="fa fa-sticky-note-o" aria-hidden="true"></i>',
          '<i class="fa fa-linux" aria-hidden="true"></i>',
          '<i class="fa fa-sun-o" aria-hidden="true"></i>',
          '<i class="fa fa-superscript" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>',
          '<i class="fa fa-sort-alpha-asc" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>',
          '<i class="fa fa-caret-square-o-down" aria-hidden="true"></i>'
      ]
  },
  methods:{
      getCat(){
        this.$http.get(this.catUrl).then(response => {
          response = response.body;
          this.categories = response;
      });
      }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="stylus" rel="stylesheet/stylus">
  @import "../assets/css/public.styl"
  .cats
    background #ffffff
    width 100%
    .categories
      width 95%
      height 100%
      overflow auto
      margin 48px auto 68px auto
      display block
      .categories-item
        text-align center
        width 100%
        height 60px
        background #ffffff
        border-bottom 1px #f2f2f2 solid
        float left
        display block
        & > a
          display block
          color #000
          height 100%
          padding 10px 0
          font-rem(16)
          & span
            float left
            padding-left 5px
            line-height 40px
            &.cat
              color #CCC
              font-rem(14)
            & i
              font-rem(14)
              color darkcyan
          & i
            float right
            padding-right 10px
            font-rem(24)
            color #CCC
            line-height 40px

</style>

八、創建一個Postcat.vue來獲取分類目錄下的文章

<template>
  <div class="psc">
    <div class="postcat">
      <div class="box" v-for="(item, index) in postcat">
        <div class="post">
          <router-link :to="{path:'/article',query: {id:postcat[index].id}}">{{postcat[index].title.rendered}}</router-link>
          <div class="line-k"></div>
          <div class="postcat-img" v-html="getFirstImg(postcat[index].content.rendered)"></div>
          <div class="description" v-html="replaceDS(postcat[index].excerpt.rendered)"></div>
        </div>
      </div>
      <a id="ipre" @click="ipre"><i class="fa fa-angle-left" aria-hidden="true"></i>PREVIOUS</a>
      <a id="inext" @click="inext">NEXT<i class="fa fa-angle-right" aria-hidden="true"></i></a>
    </div>
  </div>
</template>
<style lang="stylus" rel="stylesheet/stylus">
  @import "../assets/css/public.styl"
  @import "../assets/css/font-awesome.min.css"
.psc
  background #ffffff
  width 100%
  .postcat
    width 100%
    height 100%
    overflow auto
    margin 40px auto 68px auto
    display block
    & a
      color darkcyan
      padding 5px
      border-radius 2px
      &#ipre
        float left
        font-rem(18)
        padding 5px 10px 10px 10px
        line-height 32px
        & i
          font-rem(28)
          margin-right 10px
          float left
      &#inext
        float right
        font-rem(18)
        padding 5px 10px 10px 10px
        line-height 32px
        & i
          font-rem(28)
          margin-left 10px
          float right
    .box
      width 100%
      margin 10px auto
      background #ffffff
      padding 10px 0
      line-height 1.5
      border-bottom 6px solid #F2F2F2
      .post
        width 96%
        margin 0 auto
        & a
          color darkcyan
          background none
          font-rem(18)
          margin 0 auto 5px auto
          padding 5px 0
        .postcat-img
          width 90%
          margin 0 auto
          padding 5px 0 0 0
          & > img
            max-width 100%
            border 2px solid #CCC
            border-radius 5px
        .description
          font-rem(16)
          padding-top 5px
          color dimgrey

</style>
<script>
  export default{
    name:'ipostcat',
    data() {
      return{
        postcatUrl:'http://www.egtch.com/wp-json/wp/v2/posts?categories='+this.$route.query.id+'&page=',
        postcat:{},
        ipage: 1,
        show: false
      }
    },
    created(){
      this.getPostcat(this.ipage)
    },
    watch: {
      // 若是路由有變化,會再次執行該方法
      'ipage': 'getPostcat'
    },
    methods:{
      getPostcat(p){
        // GET /someUrl
        if(p<1){
          p = 1
        }
        this.$http.get(this.postcatUrl+p).then(response => {
          // get body data
          response = response.body
          if(response.length > 0){
            this.postcat = response
            document.getElementById('inext').style.display='block';
          }
          if(response.length < 10){
            document.getElementById('inext').style.display='none';
          }

          //alert(response);
          //console.log(this.postcat);
          //alert(this.ipage)
        })
      },
      getFirstImg(strs){
        var content = strs;
        var str = /<img [^>]*src=['"]([^'"]+)([^>]*>)/gi;
        var src = str.exec(content);
        if(src===null || src===undefined || src===[]) {
          src='';
        }else {
          src = src[0];
          src = src.replace(/ height="\d+"/g, '');
          src = src.replace(/ width="\d+"/g, '');
        }
        /*document.getElementById('imgs').src = src;
         console.log(src);
         alert(src)*/
        return src;

      },
      replaceDS(str){
        /*[&hellip;]*/
        var dc = str.replace(/\[&hellip;\]/g, '');
        return dc;
      },
      inext(){
        scrollTo(0,0);
        this.ipage++;
      },
      ipre(){
        scrollTo(0,0);
        this.ipage--;
      },
      showClose(){
        this.show = !this.show;
      }
    }
  }
</script>

以上咱們就能夠完成了得到文章以及分類目錄下的文章的相關代碼。看上去是否是很簡單,使用vuejs確實可讓咱們省去不少的DOM操做。
更多代碼和實例,請直接查看本項目在github中的實例地址爲:
https://github.com/king2088/V...,若是你喜歡本實例,請記得在github上給我加星哦!
演示地址:
http://www.egtch.com/VueEgtch/本程序會後續還會進行相應的更新維護,但願你們關注,也但願你們關注vuejs