1 Star 0 Fork 0

孙岚/VUE

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
sunlan- sunlan vue 7f29235 4年前
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

邂逅vue

一套构建用户界面的渐进式的自底向上开发的MVVM框架

渐进式

可以在原有大系统的上面,把一两个组件改用vue实现,也可以整个用vue全家桶开发,不做职责之外的事

自底向上增量开发

先写一个基础的页面,把基础的东西写好,再逐渐去添加功能和效果,有简单到繁琐的这么一个过程

渐进增强

先写兼容底层浏览器的内容,逐渐兼容高版本

优雅降级

先兼容高级版本浏览器,再逐渐向下兼容

应用vue的目的

1-解决数据绑定问题

2-开发大型单页面应用

3-组件化开发,把页面封装成组件,挺高复用性

vue核心思想

1-数据驱动

2-组件化

框架

封装与业务无关的重复代码,形成框架

渲染方式

vue的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进DOM

1-声明式编程

2-命令式编程

数据驱动

通过控制数据的变化来显示vue的数据驱动使视图的内容随着数据的改变而改变

vue中data数据可以是js任意形式

vue中数据绑定使用{{}},里面存放的是表达式--通过计算可以返回结果的公式

指令

html标签属性

写在html标签中,扩展html的功能

vue指令是什么

带有v-前缀的html特殊属性,写在html的开标签中,

指令的功能

扩展html标签的功能

具体指令

v-show

显示隐藏

v-on

绑定事件

v-model

用在表单元素中完成双向绑定

双向绑定的原理

vue数据双向绑定是通过数据劫持结合发布者--订阅者的方式来实现的

数据劫持:当我们访问或者设置对象的属性的时候,都会触发Object.defineProperty()函数来拦截(劫持),然后在返回(get)或者设置(set)对象的属性的值

发布者-订阅者模式:定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

v-model绑定复选框

v-model 绑定到表单元素中,那么他的值会自动被表单元素进行设置,如果是复选框,那么勾选上值为ture,不勾选就为false.

v-for

对数据进行遍历展示

遍历数组

v-for="(遍历的值,遍历的下标) in 要遍历的数据 "

遍历数组对象

v-for="(遍历的值,遍历的下标) in 要遍历的数据 "

v-bind

绑定html元素的属性

绑定多个属性不能使用简写

v-if

判断是否加载固定的内容,对元素进行现实和隐藏。

v-if和v-show的区别

v-if:对元素的dom进行添加和删除,高切换,安全性高

v-show:用css控制元素显示隐藏,高消耗,不安全

v-else,v-else-if

与v-if搭配使用

v-text

往指定区域插入文本

v-text与{{}}的区别

v-text叫做指令

{{}}叫模板插值,当网速慢的时候会把{{}}展示出来

v-cloak

当vue没有加载的时候先不显示,加载完毕之后再展示数据,解决屏幕闪烁的问题。不用每个都加,加在vue挂载的元素上就行。

v-html

把字符串标签解析成标签

v-once

一次性插值,只展示一次,后面数据改变页面不会跟着改变

侦听/监听watch

可以监听data模型数据 当模型数据改变的时候就会触发一个异步的方法,完成指定功能

语法

watch:{
    监听的变量(新数据,旧数据){
        consolo.log(新数据+"-----"旧数据)
    }
}
  watch:{
            inputa(newval,oldval){
                // 判断两个输入框是否为空
                if(this.inputa==""||this.inputb==""){
                    this.bool=true
                }else{
                    this.bool=false
                }
            }
        }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="demodiv">
        <!-- watch 用来监听data模型数据  当数据改变watch就会自动触发 -->
        <input type="text" v-model="text">{{text}}
    </div>
    <script >
        new Vue({
            el:"#demodiv",
            data:{
                text:"你好"
            },
            methods:{

            },
            watch:{
                text(newval,oldval){
                    console.log(newval+"-------"+oldval)
                }
            }
        })
    </script>
</body>
</html>

watch初始化的时候不会执行,只有数据改变的时候才会运行

计算属性

概念:顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了 data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。

如果一条数据需要被处理之后再进行展示的话,可以使用计算属性

或者是一条数据在不同位置展示不同的形态的时候,可以使用计算属性

语法

computed: {
        需要返回的数据: function () {
            return 处理操作
        }
    }
----------------------------------------
另一种写法:
 computed: {
        需要返回的数据() {
            return 处理操作
        }
    }    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="demodiv">
        <!-- 如果在视图中有大量的业务数据处理没有问题  但是会影响我们的代码
        可读性 官方不推荐我们这样子写 而且区公司也不能这样子写 -->
        <!-- {{text.toUpperCase()}}
        {{text}}
        {{text.toUpperCase().substr(2,3)}} -->
        <!-- 如果  一条数据需要被处理之后再进行展示的话  可以使用计算属性
        或者是 一条数据在不同位置展示数不同的形态   可以使用计算属性 -->


        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <h1>{{newtext}}</h1>
        <h1>{{newbtext}}</h1>
        <hr>
        <h1>方法</h1>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
        <h2>{{fun()}}</h2>
        <h2>{{funb()}}</h2>
    </div>
    <script >
        new Vue({
            el:"#demodiv",
            data:{
                text:"abcdefg"
            },
            methods:{
                fun(){
                    console.log("我是方法")
                    return this.text.toUpperCase() 
                },
                funb(){
                    return this.text.toUpperCase().substr(2,4) 
                }
            },
            watch:{
               
            },
            computed:{
                newtext(){
                    console.log("我是计算属性")
                    return this.text.toUpperCase()
                },
                newbtext(){
                    return this.text.toUpperCase().substr(2,4)
                }
            }
        })
    </script>
</body>
</html>

计算属性和方法有什么区别

1-计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。计算属性有缓存,方法没有缓存,方法用一次被调用一次

2-方法绑定数据只要被调用,方法将总会再次执行函数。

3-计算属性相对于方法在处理特定场合下节省资源性能

计算属性和watch的区别

两者都是对data模型数据进行相关的处理

计算属性是当传入的数据发生改变之后,计算属性会重新计算,返回新数据

watch是当监听的数据发生改变时会触发一个相关的函数

事件对象($event)

触发事件的对象

作用:记录事件相关的信息,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="demodiv">
        <input type="text" @keydown.ctrl="fun($event)">
    </div>
    <script >
        new Vue({
            el:"#demodiv",
            data:{
               
            },
            methods:{
              fun(e){
                //   console.log(e)
                //   if(e.keyCode==17){
                      console.log("用户按下了ctrl")
                //   }
              }  
            },
            watch:{
               
            },
            computed:{
               
            }
        })

    </script>
</body>
</html>

修饰符

概念:v-on指令提供了事件修饰符来处理DOM事件细节

语法

@click.修饰符='fn()'

按键修饰符

.up, .down, .ctrl, .enter, .space等等

事件修饰符

prevent修饰符:阻止事件的默认行为(submit提交表单)

stop修饰符:阻止事件冒泡

capture修饰符:与事件冒泡的方向相反,事件捕获由外到内

self:只会触发自己范围内的事件,不包含子元素

once:只会触发一次

注意:修饰符可以串联使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/vue/dist/vue.min.js"></script>


    <style>

        .fu{
            width: 500px;
            height: 500px;
            background-color: pink;
        }
        .zi{
            width: 200px;
            height: 200px;
            background-color: green;
        }
    </style>


</head>
<body>
    <div id="demodiv">
       
        <div class="fu" @click="fufun()">
            <div class="zi" @click.stop.once="zifun()"></div>
        </div>

    </div>
    <script >
        new Vue({
            el:"#demodiv",
            data:{
               
            },
            methods:{
              fufun(){
                  console.log("夫妇付付付付付付")
              },
              zifun(){
                  console.log("zizizzizizizizizzizi")
              }
            },
            watch:{
               
            },
            computed:{
               
            }
        })

    </script>
</body>
</html>

promise对象

是一个异步的解决方案,主要是为了解决回调地狱(回调函数层层嵌套)

传统的异步代码的可读性很差,使用promise可以提高可读性

promise基本用法

Promise对象是一个构造函数,用来生成promise实例。

const promise = new Promise(function(resolve,reject){
    if(/*异步操作成功*/){
       resolve(value);
}else{
       reject(error);
      }
})

promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和rejected.他们是两个函数,由js引擎提供,不用自己部署

resolve函数的作用是,将Promise对象的状态从未完成变成成功,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

rejected函数的作用是,将Promise对象的状态从未完成变为失败,在异步操作失败时调用,并将异步操作爆出的错误,作为参数传递出去。

then方法

Promise实例生成以后,可以用then方法指定resolved状态的回调函数,同时也可以用then方法指定rejected状态的回调函数,then方法执行完后返回一个新的Promise实例。

promise.then(function(value){},function(error){})

then方法可以接受两个回调函数作为参数。

第一个回调函数是Promise对象的状态变为resolved时调用。

第二个回调函数是Promise对象的状态变为rejected时调用。第二个是可选的。

这两个函数都接受Promise对象传出得值作为参数。

三个状态

padding 等待

resolve 成功

reject 失败

new Promise((resolve,reject)=>{
    resolve("成功信息")
    reject("失败信息")
})

封装jquery的ajax

 <script>
     function linkapi(url,method){
                return new Promise((resolve,reject)=>{
                    $.ajax({
                        url,
                        type:method,
                        dataType:"json",
                        success(ok){
                            resolve(ok)
                        },
                        error(err){
                            reject(err)
                        }
                    })
                })
            }         
     var a = "http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187";
     
     linkapi(a,"get").then((data)=>{
                console.log(data)
            }).catch((err)=>{
                console.log(err)
            })
    </script>

封装axios

 <script>
   function linkapi(url,method){
            return new Promise((resolve,reject)=>{
                axios({
                    url,
                    method,
                }).then((ok)=>{
                    resolve(ok)
                }).catch((err)=>{
                    reject(err)
                })
            })
        }
    var a = "http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187";
    
     linkapi(a,"get").then((data)=>{
          console.log(data)
        }).catch((err)=>{
        })
    </script>

前端和后端的概念

前端:客户端,就是浏览器(pc端 手机端)

后端:服务器(性能很好的电脑)是提供计算服务的设备。

服务器的构成包括处理器、硬盘、内存、系统总线等,和通用的计算机架构类似,但是由于需要提供高可靠的服务,因此在处理能力、稳定性、可靠性、安全性、可扩展性、可管理性等方面要求较高。

Vue生命周期

vue实例从创建到销毁的过程中有很多个阶段,在每个阶段都有一些函数会被自动执行,可以方便的帮助我们完成自动被执行调用的逻辑。

八个生命周期

<body>
<!-- 生命周期 -->
        <div id="demodiv">
            <h1>{{text}}</h1>
            <button v-on:click="text='我改了'">点我修改</button>
        </div>
        <script>
            new Vue({
                el:"#demodiv",
                data:{
                    text:"生命周期"
                },
                methods:{},
                watch:{},
                computed:{},
                filters:{},
                beforeCreate(){
                    console.log("实例创建之前")
                },
                created(){
                    console.log("实例创建之后")
                },
                beforeMount(){
                    console.log("开始创建模板")挂载前
                },
                mounted(){
                    console.log("创建模板ok")挂载后
                },
                beforeUpdate(){
                    console.log("开始更新")
                },
                updated(){
                    console.log("更新完成")
                },
                beforeDestroy(){
                    console.log("开始销毁")
                },
                destroyed(){
                    console.log("销毁完成")
                },      
            })
        </script>
</body>

描述每个生命周期

1-beforeCreate(创建前) 在数据观测和初始化事件还未开始

2-created(创建后) 完成数据观测,属性和方法的运算,初始化事件,实例中的el属性还没有显示出来

3-beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。

4-mounted(载入后) 在el 被新创建的 vue.el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。

5-beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。

6-updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。

7-beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。

8-destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

什么是vue生命周期?

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

vue生命周期的作用是什么?

生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易完成指定逻辑。

vue生命周期总共有几个阶段?

它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后

第一次页面加载会触发哪几个钩子?

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

DOM 渲染在 哪个周期中就已经完成?

DOM 渲染在 mounted 中就已经完成了。

过滤器

格式化展示数据,把展示的数据快速的展示成我们想要的内容

vue2x的时候,vue取消了内置过滤器,如果想使用过滤器就必须自定义过滤器

全局过滤器

在所有vue实例都可以使用的叫全局过滤器,必须定义在实例之前

全局过滤器的定义方法  位置:创建实例之前
Vue.filter(‘sum’, function(val){
    	return val + 4;
});

<body>
<!-- 全局过滤器
    写在实例之前
    Vue.filter("过滤器的名字随便写的",(你要过滤的数据会自动传入)=>{
        return  逻辑
    })
-->
        <div id="demodiv">
            aaaaaaaaa
            <h1>{{text|xiaoming}}</h1>
        </div>
        <div id="demodivb">
            bbbbbbbbbbb
            {{text|xiaoming}}
            <h1>{{num|xiaohong}}</h1>
        </div>
        <script>
            Vue.filter("xiaoming",(val)=>{
                return "《《"+val+"》》"
            })
            Vue.filter("xiaohong",(val)=>{
                return "¥"+val
            })
            new Vue({
                el:"#demodiv",
                data:{
                  text:"demodiv"
                                }
            })
            new Vue({
                el:"#demodivb",
                data:{
                    text:"demodivb",
                  num:19.9
                }
            })
        </script>
</body>

局部过滤器

只能在一个指定vue实例中使用的叫局部过滤器,定义在指定vue实例中,与el同级。

只能在当前vue注册内容中使用
在vue实例中与el属性data属性同级定义
filters:{
过滤器名字:function(val){
 return 输出内容
   }
}
<body>
        <div id="demodiv">
            aaaaaaaaa
            <h1>{{text|xiaoming}}</h1>
            <h1>{{textb|xiaoming}}</h1>
        </div>


        <div id="demodivb">
            bbbbbbbbbbb
            {{text}}
        </div>
        <script>

            new Vue({
                el:"#demodiv",
                data:{
                  text:"demodiv",
                  textb:"abcdefgbhjfhf"
                },
                filters:{
                    xiaoming:(val)=>{
                        return val.substr(0,4)+"..."
                    }
                }
            })

            new Vue({
                el:"#demodivb",
                data:{
                    text:"demodivb"
                }
            })
        </script>
</body>

Vue请求数据交互

三种方式

vue请求数据有Vue-resource、Axios、fetch三种方式。

Vue-resource

Vue-resource是Vue官方提供的插件,但是vue2.0之后停止更新了

Vue自身不带处理HTTP请求 如果想使用HTTP请求必须要引入 vue-resource.js 库它可以通过XMLHttpRequest发起请求并处理响应。也就是说,$.ajax能做的事情,vue-resource插件一样也能做到,而且vue-resource的API更为简洁。

Vue.js 交互借助于 $http 完成

get 类型
语法:this.$http.get(‘url’,
 	{params: {key1:val1,key2:val2…}}).
	then(function(res){处理请求成功的情况},
	function(res){处理请求失败的情况})

POST类型
语法:this.$http.post(‘url’,
 	 {key1:val1,key2:val2…},
	 {emulateJSON:true}).
	then(function(res){处理请求成功的情况},
	function(res){处理请求失败的情况})

axios

axios是第三方插件,利用promise进行了二次封装,返回的是promise对象

Axios是第三方插件,不仅能在Vue里使用,还能再其他第三方库中使用

get类型

//get类型
//语法: 
axios.get('/路径?k=v&k=v}
.then((ok)=>{})
.catch((err)=>{})

get传参

axios(utl:'请求地址',method:'请求方式',params:{k:v}).then((ok)=>{})
使用get发送数据的时候 使用params:{key:val}发送数据
import service from "@/util/service.js"


export function zhucelink(url,params){
    return new Promise((resolve,reject)=>{
        service.request({
            url,
            method:"get",
            params
        }).then((ok)=>{
            resolve(ok)
        }).catch((err)=>{
            reject(err)
        })
    })
}
<template>
  <div class="about">
    <h1>注册</h1>
    用户名: <input type="text" v-model="inputa"/>
    密码: <input type="text" v-model="inputb"/>
    <hr>
    <p>{{text}}</p>
    <button @click="fun()">注册</button>
  </div>
</template>
<script>
import {zhucelink} from "@/api/zhuceapi.js"
export default {
  data(){
    return {
      text:"",
      inputa:"",
      inputb:""
    }
  },
  methods:{
   fun(){
     zhucelink("/api/zhuce/zhuce/user",{uname:this.inputa,upwd:this.inputb}).then((ok)=>{
       console.log(ok)
       if(ok.data.data.loginid==1){
         let num=4
          setInterval(()=>{
            num--
            if(num==0){
              this.$router.push("/")
            }
          this.text="注册ok----"+num+"秒后跳转到登录页面"
          
          },1000)
       }
     })
   }
  }
}
</script>

post类型

//post类型
//语法
axios.post('/user', {k:v,k:v })
  .then(function (ok) { })
  .catch(function (error) { });

post传参

实例化对象: 
let param = new URLSearchParams();
添加发送数据参数
param.append("key", "value");
axios(utl:'请求地址',method:'请求方式',data:{k:v}).then((ok)=>{})

使用post发送数据需要使用 var param=new URLSearchParams();修改传参方法
使用param.append("uname","xixi")添加数据并且使用data发送数据
import service from "@/util/service.js"


export function loginlink(url,data){
    return new Promise((resolve,reject)=>{
        service.request({
            url,
            method:"post",
            data
        }).then((ok)=>{
            resolve(ok)
        }).catch((err)=>{
            reject(err)
        })
    })
}
<template>
  <div class="home">
    <h1>登录</h1>
      用户名: <input type="text" v-model="inputa"/>
      密码: <input type="text" v-model="inputb"/>
    <hr>
    <button @click="fun()">登录</button>
  </div>
</template>

<script>
import {loginlink} from "@/api/loginapi.js"

export default {
  name: 'Home',
  components: {
  
  },
  data(){
    return {
      inputa:"",
      inputb:""
    }
  },
  methods:{
    fun(){

      let usp=new URLSearchParams()
      usp.append("uname",this.inputa)
      usp.append("upwd",this.inputb)


      loginlink("/api/login/login/user",usp).then((ok)=>{
        console.log(ok)
        if(ok.data.data.usernum==1){
          alert("登陆成功")
          this.$router.push("/home")
        }else{
          alert("用户名密码失败!!!!!!")
        }
      })
    }
  }
}
</script>

拦截器

  • 创建url文件夹,在url中写入拦截器
import axios from "axios"
// 创建axios 赋值给常量service 
const service = axios.create();

// 添加请求拦截器(Interceptors)
service.interceptors.request.use(function (config) {
    // 发送请求之前做写什么
    return config;
  }, function (error) {
    // 请求错误的时候做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
service.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
export default service

  • 创建api文件夹,在api中封装请求
import service from "@/util/service.js"

export function homelink(url,method){
    return new Promise((resolve,reject)=>{
        service.request({
            url,
            method
        }).then((ok)=>{
            resolve(ok)
        }).catch((err)=>{
            reject(err)
        })
    })
}

图片上传的方式

form表单上传

<form action="http://localhost:3000/home/img/upload" method="post" enctype="multipart/form-data">
      <input type="file" name="logo" />
      <input type="submit" value="form上传图片提交">
</form>

axios方式提交图片

 <input type="file" ref="demo" />
 <button @click="fun()">点我上传图片</button>
 methods:{
        fun(){
            // 需要找到图片并且转换成数据流
            let imgfile=this.$refs.demo.files[0]
            var formdata=new FormData()//创建出formdata对象(异步上传文件)
            formdata.append("logo",imgfile)//添加上传文件的key 和后台接受的key要相同 imgfile就是当前得到的图片 

            imglink("/api/home/img/upload",formdata).then((ok)=>{
                console.log(ok)
            })
        }
    }
//上传图片时请求配置

import service from "@/util/service.js"

export function imglink(url,data){
    return new Promise((resolve,reject)=>{
        service.request({
            url,
            method:"post",
            data,
            cache: false, //不必须不从缓存中读取
            processData: false,//必须处理数据 上传文件的时候,则不需要把其转换为字符串,因此要改成false
            contentType: false,//必须 发送数据的格式

        }).then((ok)=>{
            resolve(ok)
        }).catch((err)=>{
            reject(err)
        })
    })
}

代理跨域

proxyTable解决跨域

//在vue.config.js中
 proxy: {
            '/api': {
              target: 'http://localhost:3000/', //对应自己的接口
              changeOrigin: true,
              ws: true,
              pathRewrite: {
                '^/api': ''
              }} }
//请求的时候,请求地址要修改

fetch

fetch es6原生

项目环境配置

修改npm镜像源

安装淘宝镜像 cnpm

vue脚手架(vue-cli)

vue脚手架---就是一个与业务无关的项目环境

vue-cli4x--2019年10月16号发布

安装命令

全局安装vue-cli

npm install -g @vue/cli

查看版本

vue --version

创建文件夹

指定项目放在那个文件夹,cd到指定文件夹路径下

创建项目

vue create 项目名

运行启动项目

cd 项目名
npm run serve

组件

概念

组件就是用来封装可复用的ui代码块,组件的本质是自定义标签

组件的分类

局部组件

全局组件

组件注意问题

  • 在组件中有多个html标签,必须用一个根节点包裹
  • 在vue组件中创建模型数据,创建data数据的时候和原来的本地模式就不一样了,因为在vue组件中,创建data数据必须对应一个函数,return一个对象
  • 在定义方法 计算属性 等,没有变化
  • 每个组件都有自己的样式,组件与组件之间的样式会发生冲突,给style设置scoped属性,就会只对当前组件生效

为什么组件的data是一个函数?

父子组件

父子组件作用域

父子组件的数据不能直接相互使用,父子组件是一个完整的独立作用域

父组件向子组件传值(正向传值)props

props期待外部传值,就是在调用组件的时候从外部把数据传递进去

  • 在data同级位置创建一个属性props:[接受的变量1,接受的变量2...]
  • 接受的变量在页面向怎么用就怎么用
  • 在组件被调用的时候 使用绑定属性的方式进行传值
//父组件
<template>
  <div class="content">
        <Bi v-for="(v,i) in arr" :key="i" :title="v.title" :imgurl="v.img"/>   
    </div>
 
</template>

<script>

import Bi from "./bottomItem.vue"
export default {
    components:{
        Bi
    },
    data(){
        return {
            futext:"我是父的数据",
            arr:[
                {title:"首页1" ,img:"img/ciwei.png"},
                {title:"首页2" ,img:"img/dianying.png"},
                {title:"首页3" ,img:"img/recommend.png"},
                {title:"首页4" ,img:"img/video.png"},
                {title:"首页5" ,img:"img/yuedu.png"},
            ]
        }
    }
}
</script>

<style>
    .content{
        width: 100%;
        height: 90px;
        border-top:1px solid red;
        position: fixed;
        bottom: 0px;
        display: flex;
        flex-direction: row;
    }
</style>
子组件
<template>
  <div class="item">
      <img :src="imgurl"/>
      <br/>
      <span>{{title}}</span>
  </div>
</template>

<script>
export default {
        data(){
            return {
                zitext:"我是子的数据"
            }
        },
        props:["title","imgurl"]
}
</script>
<style scoped>
p{
    color:pink;
}
    .item{
        flex: 1;
         text-align: center;
    }
    
    img{
        width: 25px;
        height: 25px;
    }
</style>

props验证

就是在父组件给子组件数据的时候,默认情况下任意数据类型都可以传递,但是这样会造成问题,就是子组件在使用数据的时候就没办法进行更加复杂的处理,有时必须限制数据类型,这个时候用props

props不通过的话,不会对程序的运行造成影响,但是只会在console中报一个警告

可能会遇到的问题

在进行props验证时,数据传递明显发生了错误,但是没有错误提示?

因为用vue包是压缩版本的,压缩版本把props验证的错误去掉了,如果要有错误提示,改用不压缩版本。

子组件向父组件传值(逆向传值)

  • 逆向传值是不被允许的,必须要有事件触发一个自定义事件抛出this.$emit("要定义的自定义事件名",要传递的数据)
  • 在子组件被调用的时候,用v-on自定义事件名 在组件中进行绑定=父组件的函数,但是不加(),不加()的原因是如果加了那么就会默认自动执行
  • 创建父组件中的函数,并且必须写上形参,这个形参就是子组件传递过来的数据

子组件

<template>
  <div>
      {{img}}
     <button @click="fun()">点我完成逆向传值</button> 
</div>
</template>

<script>
export default {
    props:["img"],
    methods:{
        fun(){
            this.$emit("rightpao","我是子组件的数据")
        }
    }
}
</script>

<style scoped>

</style>

父组件

<template>  
<div>
    <div class="content" v-for="(v,i) in arr" :key="i">
        <div class="left">
            <Leftzi :title="v.title"/>
        </div>
        <div class="right">
            <Rightzi :img="v.img" @rightpao="fufun"/>
        </div>
  </div>
</div>

</template>

<script>
import Leftzi from "./leftzi.vue"
import Rightzi from "./rightzi.vue"
export default {
    methods:{
        // val形参就是子组件传递过来的数据
        fufun(val){
            console.log(val)
        }
    },

    created(){
        // console.log("aaaa")
        // console.error("1aaaa")
        // console.warn("2aaaa")
    },

    data(){
        return {
            arr:[
                {title:"1111111",img:"图1片"},
                {title:"恋爱的犀牛哈哈22!!!",img:"2图片"},
                {title:"恋爱的犀牛哈哈33!!!",img:"图3片"},
                {title:"恋爱的犀牛哈哈44!!!",img:"4图片"},
                {title:"恋爱的犀牛哈哈55!!!",img:"图5片"},
                {title:"恋爱的犀牛哈哈66!!!",img:"6图片"}
            ]
        }
    },

    components:{
        Leftzi,
        Rightzi
    }
}

</script>

<style scoped>
    .content{
        display: flex;
        flex-direction: row;
        font-size: 0.16rem;
    }
    .left{
        flex: 2;
        height: 1rem;
        background-color: pink;
    }
    .right{
        flex:1;
         height: 1rem;
        background-color: green;
    }
</style>

在组件中使用v-for

为遍历数组或元素中的唯一标示,增加或删减元素时,通过这个喂一标示key判断是否是之前的元素,vue会直接对已有的标签进行复用,不会整个的将所有的标签全部删除和创建,只会重新渲染数据,然后再创建新的元素直到数据渲染完毕

slot插槽/槽口

组件中数量不同内容不同,使用的技术

具名槽口slot 就是带有名字的槽口,在定义slot的时候使用name属性来起名字,在使用的时候使用slot属性来进行插入

router路由

路由

  • 根据url的不同来调用不同的ui组件,不刷新页面的情况下,更新页面内视图。
  • 根据url锚点路径,在容器中加载不同的模块
  • 完成SPA(单页面应用)的开发

路由原理

利用锚点完成切换

路由使用/一级路由

使用配置

  1. 定义组件页面

  2. 定义路由,配置路由规则routes

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    import Home from '../views/homee.vue'
    import Dianying from '../views/dianying.vue'
    import Guangbo from '../views/guangbo.vue'
    import Tushu from '../views/tushu.vue'
    import Xiaozu from '../views/xiaozu.vue'
    
    Vue.use(VueRouter)
    
    const routes = [
      {
        path: '/home',
        name: 'Home',
        component: Home
      },
      {
        path: '/dianying',
        name: 'Dianying',
        component: Dianying
      },
      {
        path: '/guangbo',
        name: 'Guangbo',
        component: Guangbo
      },
      {
        path: '/tushu',
        name: 'Tushu',
        component: Tushu
      },
      {
        path: '/xiaozu',
        name: 'Xiaozu',
        component: Xiaozu
      },
      {path:"/",redirect:"/home"},
    
    ]
    
    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    
    export default router
    
    
  3. 创建路由实例,传入routes

    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    
    export default router
    
    
  4. 把路由实例挂载到vue实例中

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    
    
  5. 配置路由出口

      <router-view/>
    
  6. 配置路由导航router-link,浏览器会把routerlink解析成a标签,写路由导航的时候不能写成a标签。

    <template>
          <div id="nav">
            <router-link to="/home">首页</router-link>
            <router-link to="/list">列表</router-link>
            <router-link to="/jx">惊喜</router-link> 
        </div>
    </template>
    

路由导航

声明式

  • 就是使用router-link完成的路由导航
  • 对应的路由匹配成功,将自动设置class属性值.router-link-active。通过自动设置的类名方便进行路由导航样式设置。

编程式

  • 使用this.$touter.push(),全局路由的push()方法,可以回退
  • this.$router.replace()替换,不可以回退
  • this.$router.go(),正数前进,负数回退

路由重定向

重新定位方向,{path:"重定向的路径",“redirect”:"把路径调到要去的地方"}

  {path:"/",redirect:"/home"},

路由扩展

  • 设置路由规则的时候不要在path中设置/,
  • 404页面使用通配符在path中设置,不能把404的路由规则写在第一位
  {
    path: '/*',
    name: 'No',
    component: No
  },

动态路由匹配/路由传参

params

路由规则中绑定参数

  • 在路由规则的path中使用 path:"/地址/:xxx&quot

      {
        path: '/list/:id/:xiaoming',
        name: 'List',
        component: List
      },
    
  • 声明式发送参数

 <h1>声明是方式进行params路由传参</h1>
 <router-link to="/list/我是声明第一个参数">第一种方式 了解</router-link>    
 <!-- :to="{name:'你要去的路由的规则上name的值' ,parmas:{key:val}}" -->
 <router-link :to="{name:'List',params:{xiaoming:'我是声明第2个参数'}}">第2种方式</router-link>
  
  • 编程式发送参数
   methods:{
        fun(){
            this.$router.push({name:'List',params:{xiaoming:'我是编程式传参'}})
        }
    }
  • 接收参数
 <div>我是详情页面----{{this.$route.params.xiaoming}}</div>

query

使用1.发送

<router-link :to="{name:'Querylist',query:{xiaohong:'我是声明式方式进行的query传参'}}">使用声明式的方式进行query传参</router-link>
<router-link :to="{path:'Querylist',query:{xiaohong:'我是声明式方式进行的query传参'}}">使用声明式的方式进行query传参</router-link>
<router-link :to="/Querylist/?id=参数1&name=参数2">使用声明式的方式进行query传参</router-link>

js发送

this.$router.push({name:'Querylist',query:{xiaohong:'我是声明式方式进行的query传参'})
this.$router.push({path:'Querylist',query:{xiaohong:'我是声明式方式进行的query传参'})
this.$router.push("/Querylist/?id=参数1&name=参数2")

2.接收 this.$route.query.xxxx

 <h1>{{this.$route.query.xiaohong}}</h1>

params与query区别

用法上的:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。

url展示上的
params类似于post,query更加类似于我们ajax中get传参,说的再简单一点,前者在浏览器地址栏中不显示参数,后者显示,所以params传值相对安全一些。


$router和route的区别

$router是VueRouter的一个对象,router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。举例:history对象
$route是一个跳转的路由对象,每一个路由都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等 

路由模式

hash

默认的url中带#号。

history

url中没有没有没有没有没有没有#号 有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,history模式还有一个问题就是,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上。

多级路由(嵌套路由)

二级路由

  • 在一级路由的基础内嵌套子页面
  • 定义多级路由页面
  • 在指定的父级路由规则中写入children来配置子路由
  • 必须在父路由组件页面加入router-view,
  • 设置路由导航

多级路由配置规则

规则中path不带/

路由导航中这样设置

to="/一级路由/二级路由"

规则中path带/

路由导航中这样设置

to="二级路由"

路由懒加载

vue的路由技术是为了完成spa单页面应用,在第一次页面初始化的时候,路由会把所有的路由页面都渲染好--可能会造成用户的页面白屏,可以使用路由懒加载。

ES的import

 {
    path: '/phone',
    name: 'phone',
    component: () => import('../views/phone.vue')
  }

?vue异步组件懒加载--resolve

路由守卫/导航守卫

全局前置守卫

当一个导航触发时,全局前置守卫(在进入组件之前)按照创建顺序调用。
vue-router 提供的 router.beforeEach((to,from,next)=>{})可以方便地实现全局前置导航守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由
next: 下一步执行

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/login.vue'),
    // 路由独享
    beforeEnter(to,from,next){
        alert('登录后才能访问')
        next("/zhuce")
    }
  },
  {
    path: '/zhuce',
    name: 'Zhuce',
    component: () => import('../views/zhuce.vue')
  }
]

const router = new VueRouter({

  base: process.env.BASE_URL,
  routes
})

// 全局前置
router.beforeEach((to,from,next)=>{
  if(to.path=="/"||to.path=="/about"){
    alert("您没有登录请您登录后访问");
    // 去登录
    next("/login")
  }else{
     // 下一步
     next()
  }
 })
export default router

全局后置钩子

当一个导航触发时,全局后置钩子(在进入组件之后)调用。
vue-router 提供的 router.afterEach((to, from) => {})实现全局后置守卫
to:即将要进入的目标 路由对象
from: 当前导航正要离开的路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/login.vue'),
    // 路由独享
    beforeEnter(to,from,next){
        alert('登录后才能访问')
        next("/zhuce")
    }
  },
  {
    path: '/zhuce',
    name: 'Zhuce',
    component: () => import('../views/zhuce.vue')
  }
]
const router = new VueRouter({
  base: process.env.BASE_URL,
  routes
})

//全局后置
router.afterEach((to,from)=>{
  alert("欢迎您")
})
export default router

路由独享的守卫

与全局前置守卫相比路由独享守卫只是对当前路由进行单一控制参数和全局前置守卫相同
在路由配置上直接定义 beforeEnter 进行路由独享守卫定义

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/login.vue'),
    // 路由独享
      
    beforeEnter(to,from,next){
        alert('登录后才能访问')
        next("/zhuce")
    }
  },
  {
    path: '/zhuce',
    name: 'Zhuce',
    component: () => import('../views/zhuce.vue')
  }
]
const router = new VueRouter({
  base: process.env.BASE_URL,
  routes
})
export default router

组件内的守卫

组件内守卫只会对当前组件生效。
beforeRouteEnter在进入组件前调用
beforeRouteLeave离开路由之前

<template>
  <div>
      注册
  </div>
</template>
<script>
export default {
        beforeRouteLeave(to,from,next){
            if(confirm("是否离开")){
                next()
            }else{
                // flase就是什么都不执行
                next(false)
            }
        }
}
</script>
<style>
</style>

路由扩展

路由meta路由记录/路由元信息。给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,来进行一些操作,供页面组件或者路由钩子函数中使用。
 {
        path: 'demoa',
        name: 'demoa',
        meta:{
          arr:["首页","用户信息展示"],
          linktext:"用户信息展示4",
          linkicon:"el-icon-delete-solid",
          linkto:"/home/demoa"

        },
        component: () => import( '../views/er/demoa.vue')
      },
页面中使用:this.$route.meta.xxx

可以做面包屑功能

<el-breadcrumb separator="/">
  <el-breadcrumb-item v-for="(v,i) in this.$route.meta.arr" :key="i">{{v}}</el-breadcrumb-item>
</el-breadcrumb>

页面中得到路由信息 那么就可以根据路由信息动态创建 页面中的导航

页面中得到路由信息:$router.options.routes
 <router-link
            :to="v.meta.linkto"
            v-for="(v, i) in this.$router.options.routes[2].children"
            :key="i"
          >
            <el-menu-item :index="i">
              <i :class="v.meta.linkicon"></i>
              <span slot="title">{{ v.meta.linktext }}</span>
            </el-menu-item>
          </router-link>

?用户权限

mockjs模拟数据(第三方模块)

  • 创建mock文件夹,在mock中创建index.js和data文件夹

  • 下载mockjs模块

  • 在data中创建相关模拟数据的json文件,不能带注释

    {
        "arr":[
            {"name":"1xixi","age":181},
            {"name":"2xixi","age":182},
            {"name":"3xixi","age":183},
            {"name":"4xixi","age":184},
            {"name":"5xixi","age":185},
            {"name":"6xixi","age":186},
            {"name":"7xixi","age":187}
        ]   
    }
    
  • 编写index.js的mock代码

    let Mock=require("mockjs")
    Mock.mock("/home/listjson","get",require("./data/home.json"))
    
  • 在main中引用mock

    -   import Vue from 'vue'
        import App from './App.vue'
        import router from './router'
    
      Vue.config.productionTip = false
    
      require("./mock")
    
      new Vue({
        router,
        render: h => h(App)
      }).$mount('#app')
    
  • 在组件中使用

    - <template>
      <div>
          home
          <hr>
          <!-- <router-link to="/home/era">era</router-link> -->
          <!-- <router-link to="/home/erc">erc</router-link> -->
          <router-link to="/era">era</router-link>
          <router-link to="/erc">erc</router-link>
          <router-view/>
      </div>
      </template>
    
    <script>
    
    import {homelink} from "api/homeapi.js"
    
    export default {
    
        mounted(){
    
            homelink("/home/listjson","get").then((ok)=>{
    
                console.log(ok)
    
            })
    
        }
    
    }
    
    </script>
    
    

跨域

跨域违背了同源策略

开发中,基本都是前端解决跨域

上线后,后端解决跨域

在vue.config.js配置代理跨域

devServer: {
    open: true,
    port: 8088,
    proxy: {
      '/api': {
        target: 'http://localhost:8888/', //对应自己的接口
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }

在请求的时候修改请求路径

 mounted(){
       homelink("/api/ceshi","get").then((ok)=>{
           console.log(ok)
       }) 
    }

修改完重启服务

定制别名

 configureWebpack: {
    resolve: {
      alias: {
        // "别名":"对应的文件夹"
        "com": "@/components",
        "api": "@/api"
      }
    }
  }

vue.config.js中基本写法

module.exports = {

}

你在开发vue的时候 是如何解决 data数据改变了 但是视图没有改变的问题

在日常开发中或者是面试中 会遇见一个问题:为什么修改了data中的数据,但是视图没有更新?

总结这个问题就是:
当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,
向对象中添加新的属性,如果更新此属性的值,是不会更新视图的。

根据官方文档:定义如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。

受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,
所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

this.$set(要操作的数据,新增的内容,值) 

<template>
  <div>
    shop
    <h1>{{ obj.name }}</h1>
    <h1>年龄----{{ obj.age }}</h1>

    <button @click="fun()">点我添加一个age</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj: {
        name: "xixi",
      },
    };
  },
  methods: {
    fun() {
      // this.obj.age=19
      this.$set(this.obj, "age", "29");
      console.log(this.obj.age);
    },
  },
};
</script>

<style>
</style>

Vuex--状态(数据)管理工具

什么是Vuex

就是一个组件的数据仓库 把数据全部存到这个仓库中 那个组件想用 那个组件就自己去这个仓库取数据

vue是单向数据流

组件之间的传值,一旦传值完毕,接受数据的这个组件无论怎么修改,传递数据的那个组件的数据不会改变

引用配置Vuex

安装vuex

npm install vuex --save

配置vuex文件创建在src中创建store文件夹-->与store.js

单一状态树

Vuex 使用单一状态——用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 ”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。

创建store实例

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

在main.js中挂载

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

同胞/兄弟传值

第一种方式

通过父子组件传递来传值

第二种方式--中央事件总线

就是在需要传值的兄弟组件上,创建一个新的vue实例,这个实例就叫做中央事件总线

  • 在src下创建eventBus文件夹,在里面创建js文件,存放中央事件总线的vue实例

    import Vue from "vue"
    export default new Vue
    
  • 创建vue实例并且暴露

  • 在a组件中抛出需要传出的数据

    创建一个A组件,引入事件总线的js文件,接着添加一个按钮并绑定一个点击事件,进行自定义事件抛出
    
    
    
    <template>
      <div>
          我是demoa--<button @click="fun()">点我吧数据给我兄弟b</button>
      </div>
    </template>
    
    <script>
    import eventBus from "@/eventBus"
    export default {
        methods:{
            fun(){
                // 通过事件调用一个中央事件中线的自定义事件抛出
                eventBus.$emit("pao","我是demoa的数据")
            }
        }
    }
    </script>
    
    <style>
    
    </style>
    
  • 在b组件的生命周期中接收来自a组件的数据

    再创建一个B组件,引入eventBus事件总线,在mounted钩子,监听了自定义事件,并把传递过来的字符串参数传递给了on监听器的回调函数
    
    
     ```html
    
    
   ```

总结

1、创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁
2、在需要传值的组件中用bus.emit触发一个自定义事件,并传递参数(emit前加美元符)
3、在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数

$on:监听当前实例上的自定义事件

state--保存数据

state------数据源 相当于vue中的data 吧所有的数据保存在这里 

读取数据: 在想使用的组件之上使用 this.$store.state.xxxx 
也可以使用计算属性的方式进行state数据获取state里面存放的数据是响应式的
Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新

保存数据源,相当于vue中的data,保存数据的地方

读取数据,在想使用的组件上使用,this.$store.state.xxx

state里面的数据是响应式的,

存储数据

state: {//数据源  相当于vue中的data  吧所有的数据保存在这里
    text:1,
    age:18,
    bool:true,
    arr:[11111,222222,3333333,4444444],
    obj:{
      name:"xixi",
      age:19
    },
    axiosarr:[]
  },

使用数据

//要使用首先在main.js引入vuex。

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

1 可以使用$store.state.xx
{{$store.state.text}}
{{this.$store.state.text}}

2 也可以在方法中调用
  mounted(){
   console.log(this.$store.state.text)
  }
3 也可以在计算属性中调用
computed:{
    obj(){
        return this.$store.state.text
    }
}
  

mutations--修改数据

在组件中,通过this.$store.commit("需要调用的方法"),来调用mutation里面的方法

组件中

 <button @click="add()">+{{num}}</button>
 <button @click="del()">-{{num}}</button>
 data(){
        return {
            num:""
        }
    },
methods:{
        add(){
            this.$store.commit("xadd",this.num)
        },
        del(){
            this.$store.commit("xdel",this.num)
        }
    }

mutations中

mutations: {//修改
//第一个参数代表state数据源
    xadd(state,payload){   
      state.text+=payload    
    },
    xdel(state,payload){
      state.text-=payload
    },
  },

载荷--从组件给mutations传值的过程,传递方式

载荷:就是相当于从vue的组件中吧数据传递给mutations的一个过程传递的方式就是在 this.$store.commit(&quot;mustations的名字&quot;, 你要传递的数据)

如果载荷要传递多个数据 那么传递一个对象即可

this.$store.commit("mutations的名字",传递的值),传递的值也可以是对象

传值

 data(){
        return {
            num:""
        }
    },
methods:{
        add(){
            this.$store.commit("xadd",this.num)
        },
        del(){
            this.$store.commit("xdel",this.num)
        }
    }

接收

第二个参数基本上使用payload

 mutations: {//修改
    xadd(state,payload){   
      state.text+=payload    
    },
    xdel(state,payload){
      state.text-=payload
    },
  },

mutations页面刷新数据丢失问题

mutations ---- 在vuex中如果想修改数据 那么就是用mustations在组件中 通过this.$store.commit(&quot;mutations的名字&quot;)


问题 vuex数据刷新丢失vuex中页面刷新数据丢失问题

使用vue进行开发的过程中,状态管理工具一般使用vuex进行管理。
但是修改后的vuex数据存储在内存中,所以当前页面刷新数据会产生丢失现象使用H5特性本地存储流程 
监听页面刷新 
如果刷新了 就把state的数据存到本地存储中 
在实例创建完毕之后取出来替换state以保证vuex数据刷新不丢失

//解决vuex数据刷新丢失vuex中页面刷新数据丢失问题

created () {
        //在页面加载时读取localStorage里的状态信息
        if (localStorage.getItem("data") ) {
            //replaceState替换数据 Object.assign合并对象
            this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(localStorage.getItem("data"))))
        } 
        //在页面刷新时将vuex里的信息保存到localStorage里
        window.addEventListener("beforeunload",()=>{
            localStorage.setItem("data",JSON.stringify(this.$store.state))
        })
      },

actions--异步操作

actions进行操作,使用actions进行异步操作(异步请求)

Actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据(但是还是通过mutation来操作,因为只有它能操作)

页面组件通过dispath调用vuex中actions里面的方法

  mounted(){
       // 触发vuex的action
       // this.$store.dispatch("actions的名字")
    this.$store.dispatch("xlink")
    }

在actions中创建一个异步方法(方法名和触发的一样)

 actions: {//处理异步
    xlink(context){   
    }
  }

发送请求/在actions中调用请求/通过commit传递给mutations

import {apilink} from "@/api/api.js"
  actions: {//处理异步
      //context形参代表Store对象
    xlink(context){
      apilink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187","get").then((ok)=>{
        console.log(ok.data.data.commentList)
        // 传递给mutations
        //通过.commit来调用mutations对应的方法
        context.commit("axiosm",ok.data.data.commentList)
      }).catch((err)=>{
        console.log(err)
      })
    }
  },

在mutations中修改state

  mutations: {//修改
     //调用那个方法,对应的就写那个方法的名字
    axiosm(state,payload){
      state.axiosarr=payload
    }
  },

actions总结

Actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据(但是还是通过mutation来操作,因为只有它能操作)

getters---vuex中的计算属性

一条数据在不同位置展示出不同形态的时候用计算属性

使用场景:在项目开发中,有时候希望对state中的某个属性在多个组件中展示出不同状态

写法

  getters: { //vuex中的计算属性
    newtext(state) {
      return state.text.toUpperCase()
    }
  },

调用

{{this.$store.getters.newtext}}
  mounted() {
    console.log(this.$store.getters.newtext);
  },

modules---vuex的模块化

__mindmap__topic可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

__mindmap__topic使用的时候  需要创建对应存放模块的文件夹  然后在其中创建相关js文件   
之后就可以吧原本的state,mutations  actions getters等这些内容都放置到 该文件夹中       
在读取数据的时候   是this.$store.state.模块名.xxxx   剩下的操作 和没有使用modules的时候相同

在分离文件中配置

export let aboutx={
    state:{
        atext:"我是about的数据"
    }
}

在index中引入配置

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
import {aboutx} from "./modules/aboutx.js"
export default new Vuex.Store(
 {
  modules:{
    aboutx,homex,shopx
  }
 }
)

调用分离模块的方法

使用数据:$store.state.模块名.xxx

{{ this.$store.state.aboutx.text }}

ref和$refs

ref 被用来给元素或子组件注册引用信息, 引用信息将会注册在父组件的 $refs 对象上,如果是在普通的DOM元素上使用,引用指向的就是 DOM 元素,如果是在子组件上,引用就指向组件的实例。


 $refs 是一个对象,持有已注册过 ref 的所有的子组件。


  • ref注册dom元素
  • $refs 是一个对象 包含了所有被ref绑定的dom元素

使用方法

绑定到dom元素之上 直接得到这个dom元素

 <button @click="fun()">点我修改颜色</button>
 <h1 ref="demoh">我的颜色要被修改</h1>
 methods:{
    fun(){
      this.$refs.demoh.style.color="red";
    }
 }

绑定到组件之上 获取子组件的属性 方法等参数也可以完成子组件把数据给父组件

 <Zi ref="democom"/>
 <button @click="funb()">点我获取到子组件的数据</button>
 methods:{
    funb(){
      console.log(this.$refs.democom.zitext)
    }
  }

动态组件home demo/abc

  • 让多个组件使用同一个挂载点,并且动态切换,这就是动态组件,
  • 多个组件在页面中每次·只显示一个的时候,就用动态组件
  • 组件使用,在页面正常饮用,在使用的时候
<component is="变量"></component>

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">

    <div>
      home  <input type="text">
    </div>

   
    <h1>动态组件</h1>
    <button @click="fun('Demoa')">点我去demoa</button>&nbsp;&nbsp;&nbsp;
    <button @click="fun('Demob')">点我去demob</button>&nbsp;&nbsp;&nbsp;
    <button @click="fun('Democ')">点我去democ</button>&nbsp;&nbsp;&nbsp;
    <keep-alive >


        <component :is="com" ></component>


    </keep-alive>
  </div>
</template>

<script>

import Demoa from "@/components/demoa.vue"
import Demob from "@/components/demob.vue"
import Democ from "@/components/democ.vue"
export default {
  name: 'Home',
  components: {
 Demoa,Demob,Democ
  },
  data(){
    return {
      com:"Democ"
    }
  },
  methods:{
    fun(text){
        switch (text) {
          case "Demoa":
              this.com=text
            break;
          case "Demob":
              this.com=text
            break;
          case "Democ":
              this.com=text
            break;
        
        }
    }
  }
}
</script>

keep-alive

  • 组件切换后会恢复初始化,之前页面的状态会丢失
  • 用keep-alive将组件出口包裹起来,可以保存组件状态
  • 阻止组件切换的时候Dom重新渲染,减少加载事件, 提高用户体验

keep-alive的属性

include

包含的组件缓存

exclude

排除的组件不缓存,优先级大于include

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">

    <div>
      home  <input type="text">
    </div>

   
    <h1>动态组件</h1>
    <button @click="fun('Demoa')">点我去demoa</button>&nbsp;&nbsp;&nbsp;
    <button @click="fun('Demob')">点我去demob</button>&nbsp;&nbsp;&nbsp;
    <button @click="fun('Democ')">点我去democ</button>&nbsp;&nbsp;&nbsp;
      <!--Demoa被缓存-->
      <!--除了Democ,其他的被缓存-->
    <keep-alive include="Demoa" exclude="Democ">
        <component :is="com" ></component>
    </keep-alive>
  </div>
</template>

<script>

import Demoa from "@/components/demoa.vue"
import Demob from "@/components/demob.vue"
import Democ from "@/components/democ.vue"
export default {
  name: 'Home',
  components: {
 Demoa,Demob,Democ
  },
  data(){
    return {
      com:"Democ"
    }
  },
  methods:{
    fun(text){
        switch (text) {
          case "Demoa":
              this.com=text
            break;
          case "Demob":
              this.com=text
            break;
          case "Democ":
              this.com=text
            break;
        
        }
    }
  }
}
</script>

keep-alive的钩子函数--这两个生命周期函数一定是要在使用了keep-alive组件之上。

activated

在需要被激活的组件内写入,keep-alive激活时调用(进入的时候)

deactivated

在需要被激活的组件内写入,keep-alive组件停用时调用(离开的时候)

<template>
  <div>
      <h1>用户信息录入</h1>
      <div>
          <input type="text">
      </div>
      <div>
          <input type="text">
      </div>
      <div>
          <input type="text" v-xiaoming>
      </div>
      <div>
          <input type="text">
      </div>
      <div>
          <input type="text">
      </div>
  </div>
</template>

<script>
export default {
    activated() {
    console.log("1激活activated钩子函数");
  },
 
    deactivated(){
        console.log("bbbbb") 
    },

    directives:{
        "xiaoming":{
            inserted(el){
                el.focus()
            }
        }
    }
}
</script>

<style>

</style>

自定义指令

在vue内置指令不够的情况下,使用自定义指令来完成具体的功能

局部指令

<script>
export default {
    directives:{
        "xiaoming":{
            inserted(el){
                el.focus()
            }
        }
    },
}
</script>

全局指令

自定义指令的钩子函数

bind:绑定指令到元素上,只执行一次
inserted:绑定了指令的元素插入到页面中展示时调用,基本上都是操作这个钩子函数
update:所有组件节点更新时调用
componentUpdated:指令所在组件的节点及其子节点全部更新完成后调用
unbind:解除指令和元素的绑定,只执行一次 

vue打包

npm run build
在项目下面会生成一个dist文件夹就是打包好的内容 运行其中的html文件即可


解决:修改资源路径为./

module.exports = {
   
    // 基本路径
    publicPath: './', //部署应用包时的基本 URL
    outputDir: 'dist', // 输出文件目录
    assetsDir: '',//放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
    runtimeCompiler: false, //是否使用包含运行时编译器的 Vue 构建版本。设置为true可以使用template
    productionSourceMap: false,//生产环境是否生成 sourceMap 文件
    lintOnSave: true,
    chainWebpack(config) {
        config.resolve.alias
        //     .set('style', resolve('public/style'))
        config.output.filename('js/[name].[hash:16].js');//hash值设置
        config.output.chunkFilename('js/[id].[hash:16].js');
        // config.output.filename('css/[name].[hash:16].css');//hash值设置
    },
    configureWebpack: () => {
    },
    // css相关配置
    css: {
        // 是否使用css分离插件 ExtractTextPlugin
        extract: true,
        // 开启 CSS source maps?
        sourceMap: false,
        // css预设器配置项
        loaderOptions: {},
        // 启用 CSS modules for all css / pre-processor files.
        modules: false
    },
    parallel: require('os').cpus().length > 1,//是否为 Babel 或 TypeScript 使用 thread-loader
    // PWA 插件相关配置
    // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
    pwa: {},
    // webpack-dev-server 相关配置
    devServer: {
        
        open: process.platform === 'darwin',
        host: '0.0.0.0',
        port: 8888,
        https: false,
        hotOnly: false,
        // 设置代理
        proxy: {
            '/api': {
              target: 'http://localhost:3000/', //对应自己的接口
              changeOrigin: true,
              ws: true,
              pathRewrite: {
                '^/api': ''
              }
            }
          }, 
       
    },
    // 第三方插件配置
    pluginOptions: {
        // ...
    }
}

设置路由模式

router-view中的内容显示不出来
需要关闭路由的history模式,因为当前模式需要后台配合。
nginx服务器配置try_files重定向

二次封装

Mixins (混入)

扩展

  • 在操作路劲的时候,如果层级比较麻烦,那么就要使用很多路径操作,可以直接用@代替,指向src文件夹。
  • 传统的html+css+js,页面传参使用的是url传参

做项目之前要做的事

整理文件夹

api--->api.js--->封装请求
util--->service.js--->封装拦截器
mock --->{
    data-->存放json数据,
    index.js--->配置
}
store--->index.js--->vuex状态管理



建立路由页面

配置路由映射关系

配置重定向和404页面

vue.config.js配置

别名

端口

空文件

简介

取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/sun-lan/vue.git
git@gitee.com:sun-lan/vue.git
sun-lan
vue
VUE
master

搜索帮助