Web开发

Vue入门与进阶

2018-07-24  本文已影响3人  nimw

1. Vue概述

1.1 Vue介绍

Vue 是一套用于构建用户界面的渐进式框架。

1.2 Vue核心思想

  1. 双向数据绑定
    Vue双向数据绑定利用了Object对象的set()和get()方法,原理如下:
<input type="text" id="userName" >
  <span id="uName"></span>
  <script>
    const obj = {}
    Object.defineProperty(obj, 'text', {
      get: function(val) {
        console.log('get init');
      },
      set: function(val) {
        console.log('set:' + val);
        ipt.value = val;
        span.innerText = val;
      }
    })
    const ipt = document.getElementById('userName');
    const span = document.getElementById('uName');
    ipt.addEventListener('keyup', function(e) {
      obj.text = e.target.value;
    })
  </script>

1.3 Vue与React对比

1.3.1 不同点

一、Vue

二、React

1.3.2 相同点

2. Vue基础

2.1 Vue环境搭建

2.1.1 环境构建方式

  1. 官方拷贝
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  2. npm 安装
  3. vue-cli工具构建

2.1.1 vue-cli工具构建SPA应用

  1. npm i -g vue-cli
  2. vue init webpack-simple demo
    //初始化一个简单的webpack项目
  3. vue init webpack demo
    //初始化一个完整的webpack项目

2.2 Vue基础语法

  1. 模板语法
  1. ClassStyle绑定
<div v-bind:class="{active: isActive, 'text-danger': hasError}">
<div v-bind:class="[activeClass, errorClass]">
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
<div v-bind:style="{color: activeColor, fontSize: fontSize + 'px'}">
  1. 条件渲染
  1. 事件处理器
  1. Vue组件
//父组件
<template>
  <div class="hello">
    <Counter v-bind:num="num" v-on:incre="increment" v-on:decre="decrement"/>
    <span>{{`parent: ${num}`}}</span>
  </div>
</template>
<script>
import Counter from './Counter'
export default {
  data () {
    return {
      num: 10
    }
  },
  components: {
    Counter
  },
  methods: {
    increment() {
      this.num++
    },
    decrement() {
      this.num--
    }
  }
}
</script>

//子组件
<template>
  <div>
    <button @click="increment">+</button>
    <button v-on:click="decrement">-</button>
    <p><span>{{num}}</span></p>
  </div>
</template>
<script>
export default {
  props: ['num'],
  methods: {
    increment() {
      this.$emit('incre');
    },
    decrement() {
      this.$emit('decre')
    }
  }
}
</script>

2.3 路由 vue-router

2.3.1路由基础介绍

  1. 路由
    根据不同的url地址展示不同的内容或页面。
  2. 后端路由
    服务器根据url地址返回不同页面。
  3. 前端路由
    不同路由对应不同内容或页面的任务交给前端来做。
  4. 前端路由使用场景
    单页面应用。
  5. 前端路由的优缺点
    优点:路由跳转用户体验好。
    缺点:不利于SEO;浏览器前进后退重新发送请求,没有利用缓存;无法记住之前页面的滚动位置。
  6. vue-router介绍
    vue-router官网
    (1) 跳转组件
    <router-link></router-link>
    注释: router-link就是一个封装好的a标签,可以添加样式。
    (2) js跳转
    this.$router.push({path: ''})
    (3) 展示组件
    <router-view></router-view>
    注释: vue-router是对historyAPI的封装。

2.3.2. 动态路由匹配

  1. 动态路由介绍
模式 匹配路径 $route.params
/user/:username /user/even {username: 'even'}
/user/:username/post/:post_id /user/even/post/123 {username: 'even', post_id: 123}
  1. 动态路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
Vue.use(Router)
export default new Router({
  mode: 'history', //默认值为hash
  routes: [
    {
      path: '/goods/:goodsId/user/:userName',
      name: 'GoodList',
      component: GoodList
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>这是商品列表页面</div>
    <span>{{$route.params.goodsId}}</span>
    <span>{{$route.params.userName}}</span>
  </div>
</template>
<script>
export default {}

2.3.3. 嵌套路由

  1. 嵌套路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Title from '../views/Title'
import Image from '../views/Image'

Vue.use(Router)

export default new Router({
  mode: 'history', //默认值为hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList,
      children: [
        {
          path: 'title',
          name: 'title',
          component: Title
        },
        {
          path: 'img',
          name: 'img',
          component: Image
        }
      ]
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>这是商品列表页面</div>
    <router-link to="/goods/title">
      显示标题子路由
    </router-link>
    <router-link to="/goods/img">
      显示图片子路由
    </router-link>
    <div>
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
export default {}
</script>
//src/views/Image.vue文件
<template>
  <div>图片子路由</div>
</template>
<script>
export default {}
</script>
//src/views/Title.vue文件
<template>
  <div>标题子路由</div>
</template>
<script>
export default {}
</script>

2.3.4. 编程式路由

  1. 编程式路由介绍
    使用js实现页面的跳转。
  1. 编程式路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Cart from '@/views/Cart'

Vue.use(Router)

export default new Router({
  mode: 'history', //默认值为hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList
    },
    {
      path: '/cart',
      name: 'cart',
      component: Cart
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>这是商品列表页面</div>
    <button @click="toCart">
      跳转到购物车
    </button>
  </div>
</template>
<script>
export default {
  methods: {
    toCart() {
      this.$router.push({path: "/cart", query: {a: 1}})
    }
  }
}
</script>
//src/views/Cart.vue文件
<template>
  <div>
    <div>这是购物车页面</div>
    <span>{{$route.query.a}}</span>
    <button @click="backToGoods">
      返回商品列表
    </button>
  </div>
</template>
<script>
export default {
  methods: {
    backToGoods() {
      this.$router.go(-1)
    }
  }
}
</script>

2.3.5. 命名路由和命名视图

1.命名路由和命名视图介绍
给路由定义不同的名字,根据名字进行匹配。
给不同的router-view定义名字,通过名字进行对应组件的渲染。

  1. 命名路由的使用
//路由入口文件: scr/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import GoodList from '@/views/GoodList'
import Cart from '@/views/Cart'

Vue.use(Router)

export default new Router({
  mode: 'history', //默认值为hash
  routes: [
    {
      path: '/goods',
      name: 'GoodList',
      component: GoodList
    },
    {
      path: '/cart/:cartId',
      name: 'cart',
      component: Cart
    }
  ]
})
//src/views/GoodsList.vue文件
<template>
  <div>
    <div>这是商品列表页面</div>
    <router-link v-bind:to="{name: 'cart', params: {cartId:123}, query: {a:1}}">跳转到购物车页面</router-link>
  </div>
</template>
<script>
export default {}
</script>
//src/views/Cart.vue文件
<template>
  <div>
    <div>这是购物车页面</div>
    <span>{{$route.params.cartId}}</span>
    <span>{{$route.query.a}}</span>
  </div>
</template>
<script>
export default {}
</script>
  1. 命名视图
    Vue Router文档-命名视图

2.4 请求数据

2.4.1 vue-resource

  1. vue-resource 的请求API是按照REST风格设计的,它提供了7种请求API
  1. 发送请求时的options选项对象包含以下属性
参数 类型 描述
url string 请求的URL
method string 请求的HTTP方法,例如:'GET', 'POST'或其他HTTP方法
body Object, FormData string request body
params Object 请求的URL参数对象
headers Object request header
timeout number 单位为毫秒的请求超时时间 (0 表示无超时时间)
before function(request) 请求发送前的处理函数,类似于jQuerybeforeSend函数
progress function(event) ProgressEvent回调处理函数
credientials boolean 表示跨域请求时是否需要使用凭证
emulateHTTP boolean 发送PUT, PATCH, DELETE请求时以HTTP POST的方式发送,并设置请求头的X-HTTP-Method-Override
emulateJSON boolean request bodyapplication/x-www-form-urlencoded content type发送
  1. 全局拦截器interceptors
Vue.http.interceptors.push((request, next) => {
        // ...
        // 请求发送前的处理逻辑
        // ...
    next((response) => {
        // ...
        // 请求发送后的处理逻辑
        // ...
        // 根据请求的状态,response参数会返回给successCallback或errorCallback
        return response
    })
})
  1. vue-resource使用示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-resource</title>
  <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
  <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script src="../../node_modules/vue-resource/dist/vue-resource.js"></script>
</head>
<body>
<div id="app">
  <h2>vue-resource演示</h2>
  <a href="#" @click="sendGet">发送Get请求</a>
  <a href="#" @click="sendPost">发送Post请求</a>
  <a href="#" @click="sendJsonp">发送Jsonp请求</a>
  <a href="#" @click="sendHttp">全局函数</a>
  <p v-text="response"></p>
</div>

<script>

  new Vue({
    el:"#app",
    data:{
      response:''
    },
    http: {
      root: 'http://localhost:8050/imoocmall/'
    },
    mounted() {
      Vue.http.interceptors.push((request, next) => {
        console.log('request init.');
        next((response) => {
          console.log('response init.');
          return response
        })
      })
    },
    methods:{
      sendGet() {
        this.$http.get('package.json',{
          params:{
            userId: "101",
          },
          headers:{
            access_token:"abc"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendPost() {
        this.$http.post('package.json', {
          userId: '102'
        }, {
          headers: {
            access_token:"abcd"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendJsonp(){
        this.$http.jsonp("http://www.imooc.com/course/ajaxskillcourse?cid=796",{
          params:{
            userId:"1001"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        })
      },
      sendHttp() {
        this.$http({
          url:"package.json",
          method:"GET",
          params:{ userId:"103" },
          headers:{ token:"123" },
          timeout:50,
          before() {
            console.log("before init")
          }
        }).then(res => {
          this.response = res.data;
        });
      }
    }
  });
</script>
</body>
</html>

注释: ①引入 vue-resource之后可以通过this.$http的方式使用。

2.4.2 Axios

  1. Axios简介
    Axios 是一个基于 promiseHTTP 库,可以用在浏览器和 node.js 中。
  2. 请求方法介绍
  1. 执行get请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可选地,上面的请求可以这样做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  1. 执行 POST 请求
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  1. 执行多个并发请求
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));
  1. Axios使用示例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>axios</title>
  <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script src="../../node_modules/axios/dist/axios.js"></script>
</head>
<body>
<div id="app">
  <h2>vaxios演示</h2>
  <a href="#" @click="sendGet">发送Get请求</a>
  <a href="#" @click="sendPost">发送Post请求</a>
  <a href="#" @click="sendHttp">全局函数</a>
  <p v-text="response"></p>
</div>

<script>
  new Vue({
    el:"#app",
    data:{
      response:''
    },
    mounted() {
      axios.interceptors.request.use((req) => {
        console.log('request init.');
        return req;
      });
      axios.interceptors.response.use((res) => {
        console.log('response init.');
        return res;
      });
    },
    methods:{
      sendGet() {
        axios.get('../../package.json',{
          params:{
            userId: "101",
          },
          headers:{
            token:"abc"
          }
        }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendPost() {
        axios.post('../../package.json', {
          userId: '102'
          }, {
            headers: {
              token:"abcd"
            }
          }).then(res => {
          this.response = res.data;
        }).catch(err => {
          this.response = err;
        });
      },
      sendHttp() {
        axios({
          url:'../../package.json',
          method:"POST",
          data:{ userId:"103" },
          headers:{ token:"123" }
        }).then(res => {
          this.response = res.data;
        });
      }
    }
  });
</script>
</body>
</html>

注释:①axios的参数传递方式与vue-resource基本相同。② 注意区分get请求与post请求的参数传递方式。

2.4 Vue进阶

2.4.1 模拟mock数据

vue开发过程中,有时需要使用本地json模拟后台接口数据,测试前端页面展示情况。对于使用vue-cli工具构建的项目,封装了express框架,我们可以通过拦截请求的方式使用mock数据。

  1. 创建mock数据json文件
  2. webpack.dev.conf.js文件中拦截请求
//imoocmall/build/webpack.dev.conf.js文件
var goodsData = require('../mock/goods.json')
devServer: {
     before (app) {
       app.get('/goods', function (req, res) {
         res.json(goodsData);
       })
     },
    //...
}
//..

注释: 这里的app.get('/goods', (req, res) => {})就是express框架定义后端路由接口的写法。

  1. 使用mock数据
axios.get('/goods',)
  .then(res => { 
    //...
})

2.4.2 图片懒加载

使用vue-lazyload插件可以实现图片懒加载。

  1. 安装
    npm i vue-lazyload -d
  2. 引入
    main.js
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {
  error: 'dist/error.png',
  loading: 'dist/loading.gif',
})
  1. 使用
<img  v-lazy="'/static/'+good.productImage" alt="">

2.4.3 请求代理

  1. 开发过程中,前端服务与后端接口一般存在着跨域问题。vue-cli提供了proxyTable代理功能解决跨域问题。
    注释:① 开发环境前端服务端口8080(/config/index.js中的port: 8080)与后端服务端口(/server/bin/www中的var port = normalizePort(process.env.PORT || '3000');)不同,存在跨域,所有需要使用请求代理。② 一般仅在开发环境中配置。
    注意:①跨域问题只是web前端浏览器的行为,在web前端请求不符合同源策略接口数据时出现。②后端node连接mongodb数据库即使协议域名端口不同(不符合同源策略),也不存在跨域问题。
  2. 修改/config/index.js 文件中的dev.proxyTable配置
proxyTable: {
      '/goods': {
        target: 'http://localhost:3000' 
      }
    }
}

此时,当我们请求 http://localhost:8888/goods 的时候,就等于请求了http://localhost:3000/goods

proxyTable: {
      '/api': {
        target: 'http://localhost:3000' ,
        pathRewrite: {
          '^/api':  ''
        }
      }
    }
}

此时,当我们请求 http://localhost:8888/api 的时候,就等于请求了http://localhost:3000

参考资料

上一篇下一篇

猜你喜欢

热点阅读