美文网首页Web开发
Vue入门与进阶

Vue入门与进阶

作者: nimw | 来源:发表于2018-07-24 22:02 被阅读3次

    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 相同点

    • 虚拟DOM
    • 轻量级
    • 响应式
    • 服务端渲染
    • 易于集成路由工具、打包工具和状态管理工具
    • 优秀的支持和社区

    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. 模板语法
    • Mustache语法:{{msg}}
    • Html赋值:v-html = ""
    • 绑定属性: v-bind:id = ""
    • 使用表达式:{{ok ? 'YES' : 'NO'}}
    • 文本赋值:v-text = ""
    • 指令:v-if = ""
    • 过滤器:{{message | capitalize}}v-bind:id = "rawId | formtaId"
      注释: vue组件中的data推荐使用方法的方式data(){return {}}返回数据,这样不同组件实例之间就不会共用数据。
    1. ClassStyle绑定
    • 对象语法
    <div v-bind:class="{active: isActive, 'text-danger': hasError}">
    
    • 数组语法
    <div v-bind:class="[activeClass, errorClass]">
    data: {
      activeClass: 'active',
      errorClass: 'text-danger'
    }
    
    • style绑定
    <div v-bind:style="{color: activeColor, fontSize: fontSize + 'px'}">
    
    1. 条件渲染
    • v-if
    • v-else
    • v-else-if
    • v-show
    • v-cloak
    1. 事件处理器
    • v-on:click="greet"@click="greet"
    • v-on:click.stopv-on:click.stop.preventv-on:click.selfv-on:click.once
    • v-on:keyup.enter/tab/delete/esc/space/up/down/left/right
    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>
    
    • Slot

    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 {}
    
    • 使用vue-cli工具构建的项目已经嵌套vue-router
    • 路径完全匹配模式(/goods/@@@/user/&&&)才能够访问到该路由视图。
    • mode 默认取值为hash,此时通过# + 路径才能访问到。如果取值为history,则不用加#

    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>
    
    • children处注册路由时使用相对于父路由的路径即可,在router-linkto属性跳转地址要使用完整路径。
    • 从子路由的用法可知,路由的本质并不是整个页面的显示/隐藏切换,而是页面某个区域的显示隐藏切换。

    2.3.4. 编程式路由

    1. 编程式路由介绍
      使用js实现页面的跳转。
    • $router.push("name")
    • $router.push({path: "name"})
    • $router.push({path: "name?a=123})
    • $router.push({path: "name", query: {a: 123}})
    • $router.go(1/-1)
      注意: 对比区分query参数的传递与动态路由params参数的传递。 query传递的是?a=1;b=2字段,通过$route.query.key的方式取值。动态参数传递的是/a/b字段,通过$route.params.key的方式取值。
      总结:① $route.query.key获取的是当前url中query中的字段值,$route.params.key获取的是当前url中params中的字段值。②使用 router-link组件跳转和js跳转都可以传递paramsquery
    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
    • get(url, [options])
    • head(url, [options])
    • delete(url, [options])
    • jsonp(url, [options])
    • post(url, [body], [options])
    • put(url, [body], [options])
    • patch(url, [body], [options])
    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. 请求方法介绍
    • axios.request(config)
    • axios.get(url[, config])
    • axios.delete(url[, config])
    • axios.head(url[, config])
    • axios.post(url[, data[, config]])
    • axios.put(url[, data[, config]])
    • axios.patch(url[, data[, config]])
      注意: ·Axios· 请求方法中没有jsonp请求。
    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

    参考资料

    相关文章

      网友评论

        本文标题:Vue入门与进阶

        本文链接:https://www.haomeiwen.com/subject/hltumftx.html