Vue开发入门(二)

326 阅读7分钟

过滤器

过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据。

过滤器分全局过滤器和局部过滤器,下边我着重说下全局过滤器,因为全局过滤器在项目中使用频率非常高!

局部过滤器

过滤器可以用在两个地方:双花括号插值 或 v-bind表达式

<template>
    <div>
        <input type="number" v-model="money">
 		<!-- 格式: 要过滤的数据 | 过滤的方法 -->
        {{money | filter_price}}
    </div>
</template>

<script>
    export default {
        name: "FilterDemo",
        data(){
            return {
                money:0
            }
        },
        //局部过滤器
        filters:{
            filter_price(val){
                return val+"¥"
            }
        }
    }
</script>

<style scoped>

</style>

全局过滤器
  • 将过滤方法放在一个js文件中。 filter.js

    let filter_price= function(val){
           return val+"¥"
        }
    
     //导出
    export {filter_price}
    
  • 在main.js中定义全局过滤器

    import {filter_price} from './views/过滤器/filter'
    //Vue.filter(过滤器名字,过滤器方法)
    Vue.filter("filter_price",filter_price)
    

另一种导出方式(推荐使用)

 import * as filter from './components/过滤器/filter.js'
 console.log(filter);
 //先把字典中的key全部取出来,然后用forEach循环遍历,使用Vue.filter注册为全局过滤器
 Object.keys(filter).forEach(item=>{
     Vue.filter(item,filter[item])
 });
  • 组件中使用过滤器

    {{money | filter_price}}
    

vue生命周期介绍

生命周期示例

InputDemo.vue

<template>
    <div>
        <p>{{ number }}</p>
        <input type="text" name="btnSetNumber" v-model="number">

    </div>
</template>

<script>
    export default {
        name: "InputDemo",
        data(){
            return{
                number:''
            }
        },
        beforeCreate: function () {
            console.log('beforeCreate 钩子执行...');
            console.log(this.number)
        },
        created: function () {
            console.log('created 钩子执行...');
            console.log(this.number)
        },
        beforeMount: function () {
            console.log('beforeMount 钩子执行...');
            console.log(this.number)
        },
        mounted: function () {
            console.log('mounted 钩子执行...');
            console.log(this.number)
        },
        beforeUpdate: function () {
            console.log('beforeUpdate 钩子执行...');
            console.log(this.number)
        },
        updated: function () {
            console.log('updated 钩子执行...');
            console.log(this.number)
        },
        beforeDestroy: function () {
            console.log('beforeDestroy 钩子执行...');
            console.log(this.number)
        },
        destroyed: function () {
            console.log('destroyed 钩子执行...');
            console.log(this.number)
        },
    }
</script>

<style scoped>

</style>

LiveDemo.vue

<template>
    <div>
        <InputDemo v-if="show"></InputDemo>
        <button @click="show=!show">销毁输入框</button>
    </div>
</template>

<script>
    import InputDemo from './InputDemo'
    export default {
        name: "LiveDemo",
        data(){
            return{
                show:true
            }
        },
        components:{
            InputDemo
        },

    }
</script>

<style scoped>

</style>

异步回调函数

ECMAScript 6语法

  • 变量

    • var变量

      var声明变量的问题:

      可以多次重复声明同一个变量名,存在覆盖的风险

      在全局声明的变量会挂在全局对象上

      var不能形成块级作用域,例如:if、for范围外依然可以使用var声明的变量

      var声明的变量具备变量提升(hoisting)特性— 允许使用在前,声明在后

    • let变量

      ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

      {
        let a = 10;
        var b = 1;
      }
      console.log(a);
      console.log(b);
      

      上面代码在代码块之中,分别用let和var声明了两个变量。然后在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。这表明,let声明的变量只在它所在的代码块有效。

      for循环的计数器,就很合适使用let变量。

    • 常量const

      const声明一个只读的常量。一旦声明,常量的值就不能改变。

      const PI = 3.1415;
      PI // 3.1415
      
      PI = 3;
      // TypeError: Assignment to constant variable.
      

      const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

    • 字符串模板

      字符串需要用一对反引号包裹起来,它可以定义多行字符串,只用一对反引号

      要拼进去的数据需要放在${}里面
      
      大括号里面还可以进行运算,
      
      大括号里面可以调用函数
      
      • ES6以前,使用变量和字符串拼接
      var name = "王大锤";
      var age = 22
      var desc =name+",今年"+age+"岁";
      console.log(desc)
      
      • ES6语法:使用字符串模版,由反引号(波浪那个按键的引号) + ${变量名}
      var name = "王大锤";
      var age = 22;
      var desc2 = `${name},今年${age}岁`;
      console.log(desc2)
      
  • 基础语法

    • if判断

    • for循环

      在ECMAScript5(简称 ES5)中,有三种 for 循环,分别是:

      • 简单for循环

      • for-in

      • forEach

      在2015年6月份发布的ECMAScript6(简称 ES6)中,新增了一种循环,是:

      • for-of
    • 函数

      • 箭头函数
    • 解构赋值

promise对象

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

var i=10;
let pro =new Promise(function (resolve,reject) {
    console.log("进入promise")
    //模拟异步操作成功
    if (i>9) {
        //成功时,执行resolve中代码
        resolve("成功")

    }
    else {
        //失败时,执行reject中代码
        reject("失败")
    }
});

//pro.then获取到执行成功的结果
pro.then((a)=>{console.log("成功时会执行",a)});

//pro.catch获取到执行失败的结果
pro.catch((a)=>{console.log("失败时会执行",a)});

//pro.finally不管成功还是失败都会执行
pro.finally((a)=>{console.log("不管成功还是失败都会执行",a)});

vue 发送ajax请求

vue本身不支持发送AJAX请求,需要使用vue-resource、axios等插件实现

axios是一个基于Promise的HTTP请求客户端,用来发送请求,也是vue2.0官方推荐的,同时不再对vue-resource进行更新和维护

  • 安装axios并引入

    npm install axios

  • 基本用法

    使用之前学习Django时的后端代码,启动后端服务。

    使用当时的创建项目的接口作为示例

    AppProject.vue

    <template>
    <div>
        <table>
            <tr>
                <td>项目名</td>
                <td><input v-model="pro_name"></td>
            </tr>
            <tr>
                <td>版本号</td>
                <td><input v-model="pro_version"></td>
            </tr>
            <tr>
                <td>类型</td>
                <td><input v-model="pro_type"></td>
            </tr>
            <tr>
                <td>项目状态</td>
                <td><input v-model="pro_status"></td>
            </tr>
            <tr>
                <td>描述</td>
                <td><input v-model="pro_description"></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button @click="sendRequest">提交</button>
                </td>
            </tr>
    
        </table>
    </div>
    </template>
    
    <script>
        import axios from "axios"
        export default {
            name:"AppProject",
            data(){
                return {
                	//默认值
                    pro_name:"",
                    pro_version:"",
                    pro_type:"",
                    pro_status:"",
                    pro_description:""
    
                }
            },
            methods:{
                sendRequest(){
                	// 配置axios的主机、端口
                    axios.defaults.baseURL="http://localhost:8000";
                    // 配置请求头信息Content-type
                    axios.defaults.headers.post['Content-type'] = "application/json";
                    // 请求参数
                    var myData = {
                        name:this.pro_name,
                        version:this.pro_version,
                        type:this.pro_type,
                        status:this.pro_status,
                        description:this.pro_description
                    };
                    // post请求
                    axios.post("/v01/projects/",myData).then((res)=>{
                        console.log(res.data.code)
                    }).catch(()=>{
                            console.log("请求失败")
                        }
                    )
                }
            }
        }
    </script>
    
    <style scoped>
    
    </style>
    

    效果:

    注:

    1.提示跨域访问问题,在后端代码中解决:

    • 安装django-cors-headers

      pip install django-cors-headers

    • 配置settings.py文件

      # 允许访问的主机列表
      ALLOWED_HOSTS = ["*"]
      
      INSTALLED_APPS = [
          ...
          'corsheaders',
          ...
       ] 
      
      MIDDLEWARE_CLASSES = (
          ...
          'corsheaders.middleware.CorsMiddleware',
          'django.middleware.common.CommonMiddleware', # 注意顺序
          ...
      )
      
      #跨域增加忽略
      CORS_ALLOW_CREDENTIALS = True
      CORS_ORIGIN_ALLOW_ALL = True
      CORS_ORIGIN_WHITELIST = ()
      
      CORS_ALLOW_METHODS = (
          'DELETE',
          'GET',
          'OPTIONS',
          'PATCH',
          'POST',
          'PUT',
          'VIEW',
      )
      
      CORS_ALLOW_HEADERS = (
          'XMLHttpRequest',
          'X_FILENAME',
          'accept-encoding',
          'authorization',
          'content-type',
          'dnt',
          'origin',
          'user-agent',
          'x-csrftoken',
          'x-requested-with',
      )
      

    2.一次提交,会发起两个请求,一个是options请求,解决请求跨域问题,一个是真实的请求

  • axio基础配置文件

    增加axio基础配置文件,就不用每个请求都去写一遍基础信息

    import axios from "axios"
    import store from "@/store"
    
    const service = axios.create({
        baseURL:"http://127.0.0.1:8000",
        //超时时间
        timeout:10000
    });
    
    //请求拦截器
    service.interceptors.request.use(
        config=>{
            if(store.state.data){
                config.headers["Token"] = store.state.data
            }
            return config
        },
        //发送错误时
        err => {
            console.log(err)
            return Promise.reject(err)
        }
    );
    //响应拦截器
    service.interceptors.response.use(
        res=>{
            console.log(res)
            if(res.status==200){
               let response =res.data
                if(response.code == "0000"){
                    console.log("创建成功")
                }else {
                    console.log(res.message)
                }}
            else {
                console.log("未知错误")
                }
            return res
            },
        //发送错误时
        err => {
            console.log(err)
            return Promise.reject(err)
        }
    );
    
    export default service;
    

    AppProject.vue

    <template>
    <div>
        <table>
            <tr>
                <td>项目名</td>
                <td><input v-model="pro_name"></td>
            </tr>
            <tr>
                <td>版本号</td>
                <td><input v-model="pro_version"></td>
            </tr>
            <tr>
                <td>类型</td>
                <td><input v-model="pro_type"></td>
            </tr>
            <tr>
                <td>项目状态</td>
                <td><input v-model="pro_status"></td>
            </tr>
            <tr>
                <td>描述</td>
                <td><input v-model="pro_description"></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button @click="sendRequest">提交</button>
                </td>
            </tr>
    
        </table>
            <button @click="addToken">添加token</button>
    </div>
    </template>
    <script>
        // import axios from "axios"
        import axios from "./request"
        export default {
            name:"AppProject",
            data(){
                return {
                    pro_name:"",
                    pro_version:"",
                    pro_type:"",
                    pro_status:"",
                    pro_description:""
    
                }
            },
            methods:{
                sendRequest(){
                    // axios.defaults.baseURL="http://localhost:8000";
                    // axios.defaults.headers.post['Content-type'] = "application/json";
                    var myData = {
                        name:this.pro_name,
                        version:this.pro_version,
                        type:this.pro_type,
                        status:this.pro_status,
                        description:this.pro_description
                    };
                    axios.post("/v01/projects/",myData).then((res)=>{
                        console.log(res.data.code)
                    }).catch(()=>{
                            console.log("请求失败")
                        }
                    )
                },
                addToken(){
                    this.$store.commit("setData","abc123456")
                }
            }
        }
    </script>
    <style scoped>
    </style>
    
  • 请求对象

    {
    
    //“url”是将用于请求的服务器url
    
    url:'/user',
    
    //“method”是发出请求时要使用的请求方法
    
    method:'get',//默认
    
    //除非“url”是绝对的,否则“baseURL”将位于“url”的前面。
    
    //为axios实例设置'baseURL'可以方便地传递相对url
    
    //到那个实例的方法。
    
    baseURL:'https://some domain.com/api/',
    
    //“transformRequest”允许在将请求数据发送到服务器之前对其进行更改
    
    //这仅适用于请求方法“PUT”、“POST”和“PATCH”
    
    //数组中的最后一个函数必须返回字符串或ArrayBuffer
    
     transformRequest: [function (data) { 
    
    //做任何你想转换的数据返回数据;
    
    }],
    
    //“transformResponse”允许在
    
    //它传递给then/catch
    
    transformResponse: [function (data) { 
    
    //做任何你想转换的数据返回数据;
    
    }],
    
    //“headers”是要发送的自定义邮件头
    
    headers:{'X-Requested-With''XMLHttpRequest'},
    
    //“params”是与请求一起发送的URL参数
    
    params:{ID:12345};
    
    //“paramsSerializer”是负责序列化“params”的可选函数`
    
    //(例如,https://www.npmjs.com/package/qs,http://api.jquery.com/jquery.param/)
    
    paramsSerializer: function(params) { 
            return Qs.stringify(params, {arrayFormat: 'brackets'}) 
    },
    
    //“data”是要作为请求正文发送的数据
    
    //仅适用于请求方法“PUT”、“POST”和“PATCH”
    
    //如果未设置“transformRequest”,则必须是字符串、ArrayBuffer或哈希
    
    data:{firstName:'Fred'},
    
    //“timeout”指定请求超时前的毫秒数。
    
    //如果请求花费的时间超过“timeout”,则请求将被中止。
    
    timeout:1000,
    
    //“withCredentials”指示是否跨站点访问控制请求
    
    //应该使用凭据
    
    withCredentials:false,//默认
    
    //“adapter”允许自定义处理请求,从而使测试更容易。
    
    //调用“resolve”或“reject”并提供有效的响应(请参见[响应文档](#响应api))。
    
    adapter: function (resolve, reject, config) { /* ... */ }, 
    
    //“auth”表示应使用HTTP Basic auth,并提供凭据。
    
    //这将设置一个“Authorization”头,覆盖任何现有的
    
    //使用“headers”设置的“Authorization”自定义标题。
    
    auth: { username: 'janedoe', password: 's00pers3cret' }
    
    //“responseType”指示服务器将用其响应的数据类型
    
    //选项有“arraybuffer”、“blob”、“document”、“json”、“text”
    
    responseType:'json',//默认
    
    //“xsrf cookie name”是用作xsrf令牌值的cookie的名称
    
    xsrfCookieName:'XSRF-TOKEN',//默认
    
    //“xsrf header name”是承载xsrf令牌值的http头的名称
    
    xsrfHeaderName:'X-XSRF-TOKEN',//默认
    
    //“progress”允许处理“POST”和“PUT uploads”以及“GET”下载的进度事件
    
    progress: function(progressEvent) {
    
        //对本机进度事件执行任何操作
       }
    }
    
  • 响应对象

    {
    
    //“data”是服务器提供的响应
    
    data:{},
    
    //“status”是服务器响应中的HTTP状态代码
    
    status:200,
    
    //“statusText”是来自服务器响应的HTTP状态消息
    
    statusText:'ok',
    
    //`headers`服务器响应的头
    
    headers:{},
    
    //“config”是为请求提供给“axios”的配置
    
    config:{}
    
    }
    

vue-router路由的使用

什么是路由

路由,其实就是指向的意思,当我点击页面上的home按钮时,页面中就要显示home的内容,如果点击页面上的about 按钮,页面中就要显示about 的内容。Home按钮 => home 内容, about按钮 => about 内容,也可以说是一种映射. 所以在页面上有两个部分,一个是点击部分,一个是点击之后,显示内容的部分。

点击之后,怎么做到正确的对应,比如,我点击home 按钮,页面中怎么就正好能显示home的内容。这就要在js 文件中配置路由。

路由中有三个基本的概念 route, routes, router。

1, route,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。

2, routes 是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]

3, router 是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。

4,客户端中的路由,实际上就是dom 元素的显示和隐藏。当页面中显示home 内容的时候,about 中的内容全部隐藏,反之也是一样。客户端路由有两种实现方式:基于hash 和基于html5 history api.

什么是 vue-router?

  • (1)vue-router 是 Vue 官方提供前端路由插件,借助它我们实现可以基于路由和组件的单页面应用。

  • (2)它与传统的页面区别在于:

    传统的页面应用采用的是后端路由,即通过超链接来实现页面切换和跳转的。

    而在 vue-router 单页面应用中,则是通过路径之间的切换(实际上就是组件的切换)。

vue-router安装

使用vue创建项目时,已经安装了vue-router

基本使用

示例

创建vue项目时,/src/router文件下来默认有index.js文件

import Vue from 'vue'
import VueRouter from 'vue-router'
//关联的组件要导入
import MainApp from "../views/路由控制/MainApp";

Vue.use(VueRouter)

const routes = [
  {
    path: '/', //路由绑定的路径
    name: 'main', //路由的名字
    component: MainApp //路由绑定的组件
  }
  //还有其他路径,用对象形式继续写{path:'',name:'',component:''}
]

// 默认不必修改
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

App.vue

<template>
  <div id="app">
    路由占位符之上
    <!-- 路由占位符  -->
    <router-view></router-view>
    路由占位符之下
  </div>
</template>

<script>
  //  1.导入组件
  export default {
    name: "App",
    // 2. 注册组件
    components:{
    
    }
  }
</script>

<style>
</style>

启动vue应用时,先加载App.vue这个组件,加载完后根据访问的url去匹配路由,路由就会把组件信息显示到路由占位符<router-view></router-view>这个地方。

多个路由

(不同路由展示不同页面的原理)

ChildApp.vue

<template>
    <div>这是一个子应用</div>

</template>
<script>
    export default {
        name: "ChildApp"
    }
</script>

<style scoped>

</style>

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import MainApp from "../views/路由控制/MainApp";
import ChildApp from "../views/路由控制/ChildApp";

Vue.use(VueRouter)

const routes = [
  {
    path: '/main', //路由绑定的路径
    name: 'main', //路由的名字
    component: MainApp //路由绑定的组件
  },{
    path: '/child', //路由绑定的路径
    name: 'child', //路由的名字
    component: ChildApp //路由绑定的组件
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

访问 http://localhost:8081/child

访问 http://localhost:8081/main

路由跳转

(点击某个按钮跳转到另一个页面的原理)

<router-link to="跳转的path"></router-link>标签,可以通过tag标签来修改样式,默认是tag="a",即超链接。

<template>
  <div id="app">
  	<!-- 路由跳转  -->
    <router-link to="/main" tag="button">点击跳转到main</router-link> | <router-link to="/child">点击跳转到child</router-link>
    <br>
    路由占位符之上
    <!-- 路由占位符  -->
    <router-view></router-view>
    路由占位符之下
  </div>
</template>

<script>
  //  1.导入组件
  export default {
    name: "App",
    // 2. 注册组件
    components:{
    }
  }
</script>

<style>
</style>

router-link的另一种写法

<router-link :to="{path: '/main'}" tag="button">点击跳转到main</router-link> | 
<router-link :to="{path: '/child'}">点击跳转到child</router-link>

使用js的方法来实现路由跳转: (使用this.$router.push())

App.vue

<template>
  <div id="app">
    <button @click="toMain">main</button>
    <br>
    路由占位符之上
    <!-- 路由占位符  -->
    <router-view></router-view>
    路由占位符之下
  </div>
</template>

<script>
  export default {
    name: "App",
    methods:{
      toMain(){
        console.log("点击了main按钮")
        //使用js实现路由跳转
        this.$router.push({
            path: "/main"
          }
        )
      }
    }
  }
</script>

<style>
</style>

路由传参
  • params传参

    params传参,路由中必须要一个参数来接受参数

    效果

  • query传参

    要达到路由中这种形式/main?id=20的效果,使用query传参

    效果:

命名路由

前面讲了

动态路由

路由嵌套

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import MainApp from "../views/路由控制/MainApp";
import ChildApp from "../views/路由控制/ChildApp";

Vue.use(VueRouter)

const routes = [
  {
    //主路由
    path: '/main',
    name: 'main',
    component: MainApp,
    // 子路由,它的路由占位符必须写在MainApp中
    children:[
        //嵌套的路由
      {
        // 以“/”开头的嵌套路径会被当作根路径,所以子路由上不用加“/”
         path: 'child',
         name: 'child',
         component: ChildApp 
      }
    ]
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

MainApp.vue

<template>
    <div>
        hello world
        <!--   子路由的路由占位符要写在MainApp中     -->
        <router-view></router-view>
    </div>
</template>
<script>
    export default {
        name: "MainApp"

    }
</script>

<style scoped>

</style>

效果

导航守卫

element 组件库

一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的组件库,提供了配套设计资源,帮助你的网站快速成型。由饿了么公司前端团队开源。

官网 element.eleme.cn/#/zh-CN

安装

  • 安装element`-ui

    npm i element-ui -S

  • 安装依赖包

  • main.js中引入组件库和样式库

    • 按需引入:只引入需要的组件,以达到减小项目体积的目的

      main.js

      import Vue from 'vue';
      //引入Button,Select组件
      import { Button, Select } from 'element-ui';
      //引入组件样式,才能看到效果
      import 'element-ui/lib/theme-chalk/index.css';
      import App from './App.vue'
      
      Vue.component(Button.name, Button);
      Vue.component(Select.name, Select);
      /* 或写为
       * Vue.use(Button)
       * Vue.use(Select)
       */
      
      new Vue({
        el: '#app',
        render: h => h(App)
      });
      
      

      使用:原来的<button><button/>更换为<el-button @click="toMain">main</el-button>

      效果:

    • 全局引入:引入所有组件,影响性能,小项目不影响

      main.js

      import Vue from 'vue';
      //全局引入ElementUI
      import ElementUI from 'element-ui';
      //引入组件样式
      import 'element-ui/lib/theme-chalk/index.css';
      import App from './App.vue';
      // 注册ElementUI
      Vue.use(ElementUI);
      
      new Vue({
        el: '#app',
        render: h => h(App)
      });
      

layout布局

element是通过基础的24分栏,迅速简便地创建布局,因此我们也成这种布局形式为(24栅格化)

通常我们是通过 row 和 col 组件,并通过 col 组件的 span 属性我们就可以自由地组合布局

布局容器

常用组件使用

按钮组件
输入框组件
表单组件