Vue(day3)

1、Vue中的ajax:vue-resource和axios

vue-resource是Vue實現異步加載的官方庫,即Vue中的ajax。在Vue2.js以後vue-resource將再也不更新維護,因此推薦儘可能使用第三方庫axios實現異步加載。javascript

下面將對兩種庫分別進行使用說明,參考:css

vue-resourcehtml

axiosvue

一、vue-resource的使用

首先咱們須要引入庫文件:java

<script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>

vue-resourcejquery封裝的Ajax同樣,提供了簡易的api實現異步訪問。提供了 7 種請求 API(REST 風格):node

get(url, [options])
head(url, [options])
delete(url, [options])
jsonp(url, [options])
post(url, [body], [options])
put(url, [body], [options])
patch(url, [body], [options])

除了 jsonp 之外,另外 6 種的 API 名稱是標準的 HTTP 方法。jquery

具體的參數說明請參考:Vue.js-菜鳥ios

在Vue中,你能夠基於全局或組建進行異步訪問:css3

// 基於全局Vue對象使用http
Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

// 在一個Vue實例內使用$http
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);

下面咱們使用具體的案例來體驗一下。git

二、vue-resoure案例:獲取商品列表

咱們如今的需求是,使用vue-resource提供的api獲取服務端發送來的數據,並顯示出來。而後能夠添加和刪除頁面上的商品數據,併發送請求更新服務端的數據。

分析
  • 首先咱們須要從服務端獲取商品信息,因此咱們須要本身模擬一個服務端,使用Node.js來快速搭建便可。
  • 異步加載可能出現跨域的問題,咱們可使用api提供的jsonp方法進行數據的訪問,也能夠將頁面放到在Node服務器上訪問,這裏咱們使用第二種方法。
準備工做
  • 使用node搭建服務器

    首先咱們須要安裝第三方模塊:express、body-parser。

    npm install express body-parser

    書寫app.js文件:

    //加載須要的模塊
    var express = require('express');
    var app = express();
    var fs = require('fs');
    var path = require('path');
    var bodyParser = require('body-parser');
    
    //啓動服務器
    app.listen(8080, function(){
      console.log('server running at 8080');
    });
    
    //相關配置
    app.use('/views', express.static(path.join(__dirname, './views')));//靜態資源
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    
    //相關請求
    app.get('/', (req, res) => {
      res.redirect(302, '/views/index.html');
    });
  • 頁面文件index.html

    咱們把這個文件放在node文件夾的views下:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>添加信息</title>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
      <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>
    
    </head>
    <body>
      <div id="app">
          <div class="panel panel-primary">
              <div class="panel-heading">
                  <h3 class="panel-title">{{title}}</h3>
              </div>
          </div>
          <div class="panel-body form-inline">
              <label>
                  Id:
                  <input type="text" v-model="id" class="form-control" required="true" @keyup.enter="add">
              </label>
              <label>
                  Name:
                  <input type="text" v-model="name" class="form-control" required="true" @keyup.enter="add">
              </label>
              <input type="button" class="btn btn-primary" @click="add" value="添加">
              <label style="color: red;cursor: pointer;" @click="clearMessage"> {{message}} </label>
          </div>
          <table class="table table-hover table-striped table-bordered">
              <thead>
                  <tr>
                      <td>Id</td>
                      <td>Name</td>
                      <td>Date</td>
                      <td>Control</td>
                  </tr>
              </thead>
              <tbody>
                  <tr v-for="item in list" :key="item.id">
                      <td>{{item.id}}</td>
                      <td>{{item.name}}</td>
                      <td>{{item.date}}</td>
                      <td><span title="刪除" @click="deleteItem(item.id)" style="cursor: pointer;color: red;" class="glyphicon glyphicon-remove"></span></td>
                  </tr>
              </tbody>
          </table>
      </div>
    
      <script type="text/javascript">
          var vm = new Vue({
              el: '#app',
              data: {
                  list : [],
                  id:'',
                  name:'',
                  title: '添加信息',
                  message: ''
              },
              methods: {
                  add(){
                      console.log("添加");
                  },
                  clearMessage(){
                      this.message = '';
                  },
                  deleteItem(id){
                      console.log("刪除");
                  }
              }
          });
      </script>
    </body>
    </html>
  • 啓動服務器查看效果

    1550548994468

獲取信息列表
  • Node.js返回數據

    咱們使用list.json這個文件來充當數據庫。

    app.get('/getlist', (req, res) => {
      fs.readFile('./list.json', 'utf8', (err, data) => {
          if(err){
              res.json(err);
          }else{
              res.json(JSON.parse(data.toString()));
          }
      });
    });
    {
      "list":[
          {"id":"1","name":"寶馬","date":"2019/2/18"},
          {"id":"2","name":"衆泰","date":"2019/2/18"},
          {"id":"3","name":"梅賽德斯","date":"2019/2/19"},
          {"id":"4","name":"奧迪","date":"2019/2/19"}
      ]
    }
  • 使用get請求獲取信息

    getList(){
      this.$http.get('http://localhost:8080/getlist').then((res) => {
          if(!res.body){
              this.message = '信息獲取失敗'
          }else{
              this.list = res.body.list;
          }
      });
    }

    這個方法目前沒有被調用,咱們但願在頁面加載時渲染到頁面,根據Vue的生命週期,咱們可使用鉤子函數created來調用:

    created(){
      this.getList();
    },

    完整的文件最後會給出。

  • 顯示效果

    1550555730676

添加信息

信息的添加功能爲add函數,一樣的,咱們須要發送post請求(其餘方式也可),將新的數據更新到list.json文件中。

  • 頁面提交post請求

    add(){
      if(this.id.trim() == '' || this.name.trim() == ''){
          this.message = "輸入不能爲空";
          return;
      }
      //一、讀取表單信息,將信息存制list
      for(var i = 0;i < this.list.length;i++){
          if(this.list[i].id === this.id){
              this.message = "id不能重複";
              return;
          }
      }
      this.list.push({"id": this.id, "name":this.name, "date": new Date().toLocaleDateString()});
      //二、將新的list更新到json文件中
      this.setList();
    }
    setList(){
      var listObj = {
          list: this.list
      };
      this.$http.post('http://localhost:8080/setlist', {list: listObj}).then(function(result){
          if(result && +result.status === 200){
              this.message = "更新成功";
          }else{
              this.message = "更新失敗";
              this.getList();
          }
      });
    }
  • 服務器接收post請求

    app.post('/setlist', function(req, res){
      var dataStr = JSON.stringify(req.body.list);
      fs.writeFile('./list.json', dataStr, 'utf8', function(err){
          if(err){
              res.json({status: 200, message: 'ok'});
          }else{
              res.json({status: 500, message: 'failed'});
          }
      });
    });
刪除信息

刪除和添加時同樣的邏輯。

  • 頁面發送請求

    deleteItem(id){
      for(var i = 0;i < this.list.length;i++){
          if(id === this.list[i].id){
              this.list.splice(i, 1);
              i = this.list.length;
          }
      }
      this.setList();
    }
一些全局配置
Vue.http.options.root = '/root';//域名
Vue.http.headers.common['Authorization'] = 'Basic YXBpOnBhc3N3b3Jk';
Vue.http.options.emulateJSON = true;//服務器沒法編碼時使用
//若是您的Web服務器沒法處理PUT,PATCH和DELETE等REST / HTTP請求,則能夠啓用emulateHTTP選項。 這將使用實際的HTTP方法設置X-HTTP-Method-Override標頭並使用普通的POST請求。
Vue.http.options.emulateHTTP = true;
完整文件
  • app.js

    //加載須要的模塊
    var express = require('express');
    var app = express();
    var fs = require('fs');
    var path = require('path');
    var bodyParser = require('body-parser');
    
    //啓動服務器
    app.listen(8080, function(){
      console.log('server running at 8080');
    });
    
    //相關配置
    app.use('/views', express.static(path.join(__dirname, './views')));//配置靜態資源
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    
    //相關請求
    app.get('/', (req, res) => {
      res.redirect(302, '/views/index.html');
    });
    app.get('/getlist', (req, res) => {
      fs.readFile('./list.json', 'utf8', (err, data) => {
          if(err){
              res.json(err);
          }else{
              res.json(JSON.parse(data.toString()));
          }
      });
    });
    app.post('/setlist', function(req, res){
      var dataStr = JSON.stringify(req.body.list);
      fs.writeFile('./list.json', dataStr, 'utf8', function(err){
          if(err){
              res.json({status: 200, message: 'ok'});
          }else{
              res.json({status: 500, message: 'failed'});
          }
      });
    });
  • index.html

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>添加信息</title>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
      <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>
    
    </head>
    <body>
      <div id="app">
          <div class="panel panel-primary">
              <div class="panel-heading">
                  <h3 class="panel-title">{{title}}</h3>
              </div>
          </div>
          <div class="panel-body form-inline">
              <label>
                  Id:
                  <input type="text" v-model="id" class="form-control" required="true" @keyup.enter="add">
              </label>
              <label>
                  Name:
                  <input type="text" v-model="name" class="form-control" required="true" @keyup.enter="add">
              </label>
              <input type="button" class="btn btn-primary" @click="add" value="添加">
              <label style="color: red;cursor: pointer;" @click="clearMessage"> {{message}} </label>
          </div>
          <table class="table table-hover table-striped table-bordered">
              <thead>
                  <tr>
                      <td>Id</td>
                      <td>Name</td>
                      <td>Date</td>
                      <td>Control</td>
                  </tr>
              </thead>
              <tbody>
                  <tr v-for="item in list" :key="item.id">
                      <td>{{item.id}}</td>
                      <td>{{item.name}}</td>
                      <td>{{item.date}}</td>
                      <td><span title="刪除" @click="deleteItem(item.id)" style="cursor: pointer;color: red;" class="glyphicon glyphicon-remove"></span></td>
                  </tr>
              </tbody>
          </table>
      </div>
    
      <script type="text/javascript">
          var vm = new Vue({
              el: '#app',
              data: {
                  list : [],
                  id:'',
                  name:'',
                  title: '添加信息',
                  message: ''
              },
              created(){
                  this.getList();
              },
              methods: {
                  add(){
                      if(this.id.trim() == '' || this.name.trim() == ''){
                          this.message = "輸入不能爲空";
                          return;
                      }
                      //一、讀取表單信息,將信息存制list
                      for(var i = 0;i < this.list.length;i++){
                          if(this.list[i].id === this.id){
                              this.message = "id不能重複";
                              return;
                          }
                      }
                      this.list.push({"id": this.id, "name":this.name, "date": new Date().toLocaleDateString()});
                      //二、將新的list更新到json文件中
                      this.setList();
                  },
                  setList(){
                      var listObj = {
                          list: this.list
                      };
                      this.$http.post('http://localhost:8080/setlist', {list: listObj}).then(function(result){
                          if(result && +result.status === 200){
                              this.message = "更新成功";
                          }else{
                              this.message = "更新失敗";
                              this.getList();
                          }
                      });
                  },
                  clearMessage(){
                      this.message = '';
                  },
                  deleteItem(id){
                      for(var i = 0;i < this.list.length;i++){
                          if(id === this.list[i].id){
                              this.list.splice(i, 1);
                              i = this.list.length;
                          }
                      }
                      this.setList();
                  },
                  getList(){
                      this.$http.get('http://localhost:8080/getlist').then((res) => {
                          if(!res.body){
                              this.message = '信息獲取失敗'
                          }else{
                              this.list = res.body.list;
                          }
                      });
                  }
              }
          });
      </script>
    </body>
    </html>

    三、axios的使用

axios的使用同vue-resource基本一致。咱們使用axios重寫上面獲取信息列表的方法就一目瞭然了:

  • 導入庫文件

    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  • 重寫getList

    getList(){
      axios.get('http://localhost:8080/getlist').then((res) => {
          if(!res.data){
              this.message = '信息獲取失敗'
          }else{
              this.list = res.data.list;
          }
      });
    }

    能夠發現,this.$http.get() 變成了 axios.get(),而response返回的數據存在data中而不是body中。

更多細節請參考:axios

2、過濾和動畫

一、css3過渡和動畫簡介

過渡

看下面的例子:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        div{
            width: 100px;
            height: 100px;
            background-color: #999111;
        }
        div:hover{
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    <div></div>
</body>
</html>

當咱們的鼠標懸浮在div元素上時,元素的樣式發生了變化,可是這是瞬時變化的,在CSS3加入過渡和動畫以前,元素屬性(樣式)變化都是沒有時間軸的。

爲了提升用戶體驗,CSS3實現了元素的過渡和動畫效果。在上面的例子中,咱們使用爲元素加上過渡屬性:transition

div{
    width: 100px;
    height: 100px;
    background-color: #999111;
    transition: all 1s ease;
}

這樣,咱們就能看到元素在樣式變化過程當中的過渡效果。

關於transition的更多用法請自行查閱。

動畫

對於過渡來講,咱們須要事件觸發才能看到效果,即存在狀態變化,且過渡只在元素的兩個狀態之間變化。不少時候咱們不須要事件觸發也能實現狀態變化,且能控制變化狀態。這就是更復雜的動畫功能,使用animation屬性。

動畫比過渡多了狀態控制的過程,因此css動畫須要結合keyframes(關鍵幀)來結合animation屬性使用。

更多相關屬性可自行查閱學習。

這裏有一個css動畫案例:行星運動

參考:

http://www.runoob.com/css3/css3-animations.html

http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html

二、Vue中的過濾和動畫

詳情請參考官方文檔:https://cn.vuejs.org/v2/guide/transitions.html

概述

在Vue中,能夠在插入、更新或移除DOM時提供不一樣方式的過渡效果:

  • 使用class類
  • 配合使用第三方css動畫插件,如Animated.css
  • 使用js
  • 配合使用第三方js動畫插件,如Velocity.js

這些本質上都是CSS過渡和動畫的封裝實現,只是可讓咱們使用更少的代碼實現更多的功能(需求)

過渡的類

Vue把過渡分爲兩個階段來實現過渡效果,分別是進入階段、離開階段。而這兩個階段又再細分爲前和後兩個階段,具體如圖所示:

Transition Diagram

下面是一個簡單的例子:

因爲Vue能在適當的時機添加類,因此不須要咱們手動綁定類名,可是咱們須要使用Vue提供的Transition組件來包裹須要過渡的元素。

<div id="app">
    <button @click="show = !show">Toggle</button>
    <transition>
        <h3 v-show="show">This is a message.</h3>
    </transition>
</div>
.v-enter-active, .v-leave-active{
    transition: all 0.8s ease;
}
.v-enter, .v-leave-to{
    transform: translateX(10px);
    opacity: 0;
}
var app = new Vue({
    el: '#app',
    data: {
        show: true,
    }
});

transition的name屬性能夠自定義類名的前綴,如name="my-transition",那麼類名就變成my-transition-enter等。

自定義過渡的類名:使用第三方css庫

Vue提供了自定義過渡類名的特性:

  • enter-class
  • enter-active-class
  • enter-active-to(2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class(2.1.8+)

這樣咱們就可使用自定義的類名來定義不一樣的過渡效果,下面咱們結合第三方css庫來使用:

<button @click="show = !show">Toggle</button>
<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
    <h3 v-show="show">This is a message.</h3>
</transition>
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">

咱們使用了Animation.css提供的類樣式:animated、bounceIn和bounceOut。只須要放在適合的類中便可自動加載觸發。

Vue動畫

CSS 動畫用法同 CSS 過渡,區別是在動畫中 v-enter 類名在節點插入 DOM 後不會當即刪除,而是在 animationend 事件觸發時刪除。

js鉤子

上面咱們能夠經過類名來控制過渡效果,下面咱們還可使用js鉤子函數來控制:

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

還有不少的Vue動畫特性,這樣再也不贅述,可自行到官網查閱學習。

3、組件

 組件名

給一個組件註冊一個符合其用途的名稱是咱們應當考慮的,且儘可能遵循W3C規範,即名稱全小寫,必要的單詞以以字符分隔開。例如:

Vue.component('show-number', {/*...*/});

Prop

一、prop的命名

在html中特性名稱prop是大小寫不敏感的,瀏覽器會將大寫當作小寫來處理,因此駝峯式(camelCase)的寫法能夠換成連字符的寫法(kebab-case)。

二、props的類型

有兩種寫法:

  • 字符串數組形式:
    js props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

  • 對象形式:

    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object
    }

推薦使用對象形式,由於這種不但清晰地標明瞭數據類型,還能在js報錯的時候發出相應的信息提示。

三、靜態賦值和動態賦值

所謂的靜態賦值就是將一個不變的數據傳給prop,而動態賦值就是將一個變量傳給prop,以此來達到動態賦值的效果。

  • 靜態

    <my-component titile="Boom"></my-component>
  • 動態

    <my-component :title="data.title"></my-component>
    <my-component :title="'this is' + data.title"></my-component>

雖然咱們都是在傳遞一個字符串,但理論是支持任意類型的數據。須要注意的是,若是咱們但願傳遞一個數字就不能單純的使用靜態賦值,由於這樣會變被當成字符串來處理。一樣的道理,對於Boolean值、數組、對象,咱們都須要使用動態賦值來保證數據的類型。

  • 一次性賦值

    若是你但願將全部的prop做爲整個對象傳入,可使用不帶名稱的v-bind進行賦值。例如:假定有一個對象

    props = {
        id: 1,
        title: 'hiahia'
    }

    一次性賦值:

    <my-component v-bind="props"></my-component>

    等價於:

    <my-component :id="props.id" :title="props.title"></my-component>
四、單向流數據

全部的prop都使得其父子之間的prop造成一個單向下行綁定:父級更新將會更新子組件的prop,但反過來卻不行,因此Vue不容許在子組件中出現修改prop的狀況。

五、prop驗證

上面提到的推薦的prop類型是對象類型,咱們能夠對組件進行驗證性信息傳入,當不符合註冊規則是發出錯誤信息。如:

Vue.component('my-component', {
  props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會經過任何類型驗證)
    propA: Number,
    // 多個可能的類型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 帶有默認值的數字
    propD: {
      type: Number,
      default: 100
    },
    // 帶有默認值的對象
    propE: {
      type: Object,
      // 對象或數組默認值必須從一個工廠函數獲取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數
    propF: {
      validator: function (value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})
六、禁用特性繼承

若是你不但願組件的根元素繼承特性,那麼你能夠在註冊是加上這個特性:inheritAttrs: false

本站公眾號
   歡迎關注本站公眾號,獲取更多信息