Skip to content

Vue 学习笔记

Vue.js是一套用于构建用户界面的渐进式框架。
Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层。
提前掌握HTML,CSS,JavaScript,AJAX基础知识

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./js/main.js"></script>

在 Vue 中,引入了 "键盘修饰符" 。简单来说,它将一些常用的按键起了个名字,让我们无需再记忆那些枯燥的键码值。
比如:
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right

Vue基础

插值表达式
{{ message }}

el:挂载点 通过css属性设置Vue实例管理的元素
可以使用其他的选择器,但是建议使用ID选择器
可以使用其他的双标签,不能使用HTML和BODY
作用范围在el命中的元素内部及其内部的后代元素

data:数据对象
Vue中用到的数据定义在data中
data中可以写复杂类型的数据,包括对象,数组等
渲染复杂类型数据时,遵守js的语法即可
例如:
var app = new Vue({
    el:"#app",
    data:{
        message:"你好 小黑",
        school:{
            name:"黑马程序员",
            mobile:"15716800846"
        },
        campus:["北京","上海","广州","深圳"]
    }
})
调用数据对象
<h2>{{ school.name }} {{ school.mobile }}</h2>
<ul>
    <li> {{ campus[0] }} </li>
    <li> {{ campus[1] }} </li>
    <li> {{ campus[2] }} </li>
    <li> {{ campus[3] }} </li>
</ul>

methods方法和data数据对象是平级关系

Vue本地应用

Vue指令
v-text v-html v-on基础 v-show v-if v-bind v-for v-on补充 v-model

v-once只执行一次
v-pre跳过这个元素和它的子元素的编译过程
v-cloak: 防止页面加载时闪动一下
方法:在 html 中的加载点加上 v-cloak,页面解析完成会移除这个属性
<ul v-cloak v-for="item in obj">
     <li>{{ obj.name }}</li>
</ul>
然后在css中添加
[v-cloak] {
     display: none;
}

v-text 设置元素的文本值(textContent)
字符串的拼接必须用单引号,插值表达式里边单引号和双引号都可以
<h2 v-text="message+'!'"></h2>
<h2>深圳{{ message+"!" }}</h2>
如果进行部分替换就用插值表达式的写法
v-text会替换标签里边全部内容

v-html
设置元素的innerHTML
内容中有html结构会被解析为文本

v-on基础
v-on也可以写作@
v-on:click="dolt"
@click="dolt"
methods:{
    dolt:function(){
        //一个函数
    }
}

计数器
data:{
    num:1
},
methods:{
    add:function(){
        // console.log('jia');
        if(this.num<10){
            this.num++;
        }else{
            alert('别点了,最大了!');
        }
    },
    sub:function(){
        // console.log('jian');
        if(this.num>0){
            this.num--
        }else{
            alert('别点了,最小了!');
        }
    }
}

v-show
根据表达值的真假,切换元素的显示和隐藏
v-show="true"
v-show="flase"
data:{
    isShow:false
},
methods:{
    changeIsShow:function(){
        this.isShow = !this.isShow;
    }
}

v-if
v-if指令的作用是:根据表达式的真假切换元素的显示状态
本质是通过操纵dom元素来切换显示状态
表达式的值为true,元素存在于dom树中,为false,从dom树中移除
<div id="app">
    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
</div>

v-bind
v-bind指令的作用是:为元素绑定属性
完整写法是v-bind:属性名
简写的话可以直接省略v-bind,只保留:属性名
v-bind动态绑定class

对象语法
 <h2 :class="{类名:布尔值,类名:布尔值}">{{message}}</h2>
 当布尔值为true,添加这个类名,否者删除
 
 动态绑定class
 :class="{active:tabNumber == 1}"
 
 数组语法
 <h2 :class="[active,line]">{{message}}</h2>
 
 <div :class="['dot','dot2',{'dotWhite':progress == 2 || progress == 3},{'dot40':progress == 2 || progress == 3},{'dotOk':progress == 3}]"></div>
 
 动态绑定style同理

v-for
v-for指令的作用是:根据数据生成列表结构
数组经常和v-for结合使用
语法是(item,index) in 数据
item和index可以结合其他指令一起使用

当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识
Diff算法就可以正确的识别此节点
找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。


v-on补充
事件绑定的方法写成函数调用的形式,可以传入自定义参数
定义方法时需要定义形参来接收传入的实参
事件的后面跟上.修饰符可以对事件进行限制
.enter可以限制触发的按键为回车

V-model
获取和设置表单元素的值(双向数据绑定)
v-model指令的作用是便捷的设置和获取表单元素的值
绑定的数据会和表单元素值相关联
绑定的数据←--→表单元素的值

lazy修饰符:
默认情况下,v-model默认是在input事件中同步输入框的数据的。
也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新:
number修饰符:
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型:
trim修饰符:
如果输入的内容首尾有很多空格,通常我们希望将其去除
trim修饰符可以过滤内容左右两边的空格


小黑记事本
新增,删除,统计,清空,隐藏
列表结构可以通过v-for指令结合数据生成
v-on结合事件修饰符可以对事件进行限制比如.enter
v-on在绑定事件时可以传递自定义参数
通过v-model可以快速的设置和获取表单元素的值
基于数据的开发方式
1 新增
生成列表结构(v-for数组)
获取用户输入(v-model)
回车新增数据(v-on .enter 添加数据)
2 删除
点击删除指定内容(v-on splice索引)
3 统计
统计信息个数(v-text length)
4 清空
点击清除所有信息(v-on清空数组)
5 隐藏
没有数据时,隐藏元素(v-show v-if数组非空)

Vue网络应用

axios(功能强大的网络请求库)的基本使用
axios 网络请求库 内部为Ajax
文档传送门
https://github.com/axios/axios
axios必须先导入才可以使用
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
使用get或post方法即可发送对应的请求
axios.get(地址?key=value&key2=values).then(function(参数){请求完成执行的函数},function(参数){请求失败执行的函数})
axios.post(地址,{key:value,key2:value2}).then(function(参数){},function(参数){})
then方法中的回调函数会在请求成功或失败时触发
通过回调函数的形参可以获取响应内容,或错误信息

axios+Vue
axios回调函数中的this已经改变,无法访问到data中数据
把this保存起来,回调函数中直接使用保存的this即可
和本地应用的最大区别就是改变了数据来源

// axios模块封装
// request.js文件
// import axios from 'axios'

// export function request(config) {
//   const instance = axios.create({// 创建axios的实例
//     baseURL: 'http://123.207.32.32:8000',
//     timeout: 5000
//   })
//   return instance(config)// 3.发送真正的网络请求
// }

// 其他文件使用
// request({
//   url: '/home/multidata'
// }).then(res => {
//   console.log(res);
// }).catch(err => {
//   console.log(err);
// })

Vue结合网络数据开发应用
axios结合Vue制作天气预报案例
1)
回车查询
1.按下回车(v-on .enter)
2.查询数据(axios 接口 v-model)
3.渲染数据(v-for 数组 that)
天气接口
●请求地址:
http://wthrcdn.etouch.cn/weather_mini
●请求方法: get
●请求参数: city (查询的城市名)
●响应内容:天气信息
2)点击查询
1.点击城市(v-on自定义参数)
2.查询数据(this.方法())
3.渲染数据(this.方法())
自定义参数可以让代码的复用性更高
methods中定义的方法内部,可以通过this关键字点出其他的方法

Vue综合应用
悦听--音乐播放器
1 歌曲搜索
2 歌曲播放
3 歌曲封面
4 歌曲评论
5 播放动画
6 mv播放

Vue生命周期
通俗的说,生命周期就是从出生到死亡的历程。

Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等一系列过程,我们成为Vue 实例的生命周期,钩子就是在某个阶段给你一个做某些处理的机会。

beforeCreate( 创建前 )
在实例初始化之后,数据观测和事件配置之前被调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。
created ( 创建后 )
实例已经创建完成之后被调用,在这一步,实例已完成以下配置:数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始, $el属性目前不可见,这是一个常用的生命周期,因为你可以调用methods中的方法,改变data中的数据,并且修改可以通过vue的响应式绑定体现在页面上,,获取computed中的计算属性等等,通常我们可以在这里对实例进行预处理,也有一些童鞋喜欢在这里发ajax请求,值得注意的是,这个周期中是没有什么方法来对实例化过程进行拦截的,因此假如有某些数据必须获取才允许进入页面的话,并不适合在这个方法发请求,建议在组件路由钩子beforeRouteEnter中完成
beforeMount
挂在开始之前被调用,相关的render函数首次被调用(虚拟DOM),实例已完成以下的配置: 编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上。
mounted
挂在完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次。
beforeUpdate
在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加地重渲染过程
updated(更新后)
在由于数据更改导致地虚拟DOM重新渲染和打补丁只会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器端渲染期间不被调用
beforeDestroy(销毁前)
在实例销毁之前调用,实例仍然完全可用,
这一步还可以用this来获取实例,
一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件
destroyed(销毁后)
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用

搭建Vue-cli并创建一个项目:
安装nodeJs
利用淘宝镜像安装cnpm:npm install cnpm -g --registry=https://registry.npm.taobao.org
全局安装Vue-cli:npm install -g vue-cli
创建一个基于webpack模板的项目:vue init webpack 项目名称
安装项目所需要的依赖:npm install
运行项目:npm run dev
退出:ctrl+c,y
打包上线:npm run build

当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。
使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符。
有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作。
<style scoped>
.a >>> .b { /* ... */ }
</style>

<router-link to="./father">这个相当于a链接</router-link>

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个 attribute 绑定上去
具名插槽可以使用缩写,v-slot可以使用#来代替(该缩写只在其有参数的时候才可用)

axios get 获取数据
<template>
  <div class="app-container">
        <input type="text" :value="name" >
    </div>
</template>

<script>
import axios from "axios";
export default {
      data () {
        return {
            name:''
        }
      },
        mounted () {    
            var that = this;
            axios.get("https://autumnfish.cn/api/joke").then(function(e){
                that.name = e.data;
            })
        }
}
</script>

@click.stop 阻止事件冒泡
@click.prevent 阻止事件的默认行为,
<a href="http://www.baidu.com" @click.prevent="test4">百度一下</a>   //阻止a标签跳转,仅执行函数test4
<form  action="/xxx"   @submit.prevent="test5">   //阻止表单提交,仅执行函数test5
         <input type="submit" value="注册">
</form>
按键修饰符 @keyup.enter

//按下enter时,执行方法test7
<input type="text" @keyup.enter="test7">
methods: {
      test7 (event) {
        console.log(event.keyCode)
        alert(event.target.value)
      }
}

Vue内置组件
component
可以切换组件的显示,选项卡效果就可以用到这个
<template>
    <!-- 父组件 -->
    <div id="app">
      <button @click="change1">son1</button>
      <button @click="change2">son2</button>
      <component :is='state'></component>
    </div>
</template>

<script>
import son1 from './components/son1.vue';
import son2 from './components/son2.vue';
export default {
        data () {
            return {
                state: 'son1'
            }
        },
        components: {
            son1,
            son2
        },
        methods:{
            change1() {
                this.state = 'son1'
            },
            change2() {
                this.state = 'son2'
            }
        }
}
</script>

transition
动画
.fade-enter{ } 进入过渡的开始状态,元素被插入时生效,只应用一帧后立即删除;(运动的初始状态)
.fade-enter-active{ } 进入过渡的结束状态,元素被插入时就生效,在 transition/animation 完成之后移除。这个类可以被用来定义过渡的过程时间,延迟和曲线函数。
.fade-leave{ } 离开过渡的开始状态,元素被删除时触发,只应用一帧后立即删除;
.fade-leave-active{ } 离开过渡的结束状态,元素被删除时生效,在 transition/animation 完成之后移除。这个类可以被用来定义过渡的过程时间,延迟和曲线函数。

自定义过度类名
默认的.fade-enter变成.fade-in-enter;
默认的.fade-enter-active变成.fade-in-active;
默认的.fade-leave变成.fade-out-enter;
默认的.fade-leave-active变成.fade-out-active;
<transition 
 name="fade"
 enter-class="fade-in-enter"
 enter-active-class="fade-in-active"
 leave-class="fade-out-enter"
 leave-active-class="fade-out-active"
>
 <p v-show="show">hello</p>
</transition>

transition相关函数
<transition name="fade"
 @before-enter="beforeEnter"
 @enter="enter"
 @after-enter="afterEnter"
 @before-leave="beforeLeave"
 @leave="leave"
 @after-leave="afterLeave"
>
 <p v-show="show">world</p>
</transition>

methods:{
  beforeEnter(el){
      console.log('动画enter之前');
  },
  enter(el){
      console.log('动画enter进入');
  },
  afterEnter(el){
      console.log('动画进入之后');
      el.style.background="blue";
  },
  beforeLeave(el){
      console.log('动画leave之前');
      el.style.background="red";
  },
  leave(el){
      console.log('动画leave');
  },
  afterLeave(el){
      console.log('动画leave之后');
  }
}

transition-group
transition过渡标签,它只对一个元素有效果,它主要给v-if,v-show,动态组件等添加过渡效果,也就是一个元素/组件从无到有,从有到无,的过程添加一些动态效果。 
和 <transition> 组件相比,<transition> 是一个抽象组件,且只对单个元素生效。而 <transition-group> 组件实现了列表的过渡,并且它会渲染一个真实的元素节点。

keep-alive
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
例如
用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。
keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。总的来说,keep-alive用于保存组件的渲染状态。

mixins是一种分发Vue组件中可复用功能的一种灵活方式。
通俗的说页面有相同的功能可以封装成组件来使用,那么多个组件有相同的功能可以封装成mixin。
//这是定义一个混入
export const hunru = {
    methods:{
        showName(){
            alert(this.name)
        }
    }
}
//这是组件中引入混入
import {hunru} from '../../../mixins/mixin.js'
mixins:[//和data同级
    hunru
]

vue链接跳转
    <router-link to="/about">关于我们</router-link>
    ||
    onClick() {
      this.$router.push('/about');
    },
vue跳转外部链接
window.location.href = url;

Vue中的MVVM
View依然是我们的DOM
Model就是我们我们抽离出来的obj
ViewModel就是我们创建的Vue对象实例

方法和函数的区别:
  1)函数是一段代码,通过名字来进行调用。它能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值。
  所有传递给函数的数据都是显式传递的。函数和对象无关。
  2)方法也是一段代码,也通过名字来进行调用,但它跟一个对象相关联,方法是和实例相挂钩的。方法和函数大致上是相同的,但有两个主要的不同之处:
  方法中的数据是隐式传递的;方法和对象相关。
  方法可以操作类内部的数据(请记住,对象是类的实例化–类定义了一个数据类型,而对象是该数据类型的一个实例化)

methods里边定义的是方法。

计算属性
<h2>总价格:{{totalprice}}</h2>
computed里边是一个属性,不要当成函数,调用直接写属性值

data: {
    books: [
        {id: 110,name:'unix编程艺术',price: 119},
        {id: 111,name: '代码大全',price: 105},
        {id: 112,name: '深入理解计算机原理',price: 98},
        {id: 113,name: '现代操作系统',price: 87},
    ]
},
computed:{
    totalprice: function () {let result = o
    for (let i=o; i < this.books. length; i++){
        result += this.books[i].price
    }
    return result
}
每一个计算属性都包含一个getter 和一个setter ;绝大多数情况下,我们只会用默认的getter 方法来读取一个计算属性,在业务中很少用到setter,所以在声明一个计算属性时,可以直接使用默认的写法,不必将getter 和setter 都声明。但在你需要时,也可以提供一个setter 函数, 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发setter 函数
computed : {
    totalPrice : {
        get : function() {

        },
        set : function() {

        }
    },
    fullName : {
        get : function() {

        },
        set : function() {
            
        }
    }
}

$event是指当前触发的是什么事件(鼠标事件,键盘事件等)
$event.target则指的是事件触发的目标,即哪一个元素触发了事件,这将直接获取该dom元素
<button @click="console.log($event.target.name)" name="哈哈">单击</button>
//哈哈

模块化
多人开发项目,每个人负责项目的某个模块,若没有模块化思想,各模块之间定义的变量,方法很容易交杂在一起导致错误。
可维护性高,避免函数名,变量名冲突,相同名字的函数和变量完全可以分别存在不同的模块中,不必考虑名字会与其他模块冲突。
模块化实现的基本思想——闭包,在匿名函数内部,定义一个对象
给对象添加各种需要暴露到外面的属性和方法
将这个对象返回,然后接收

路由
$ router只写要跳转的路由, $ route 只读(参数的获取)

Vue循环出来的数据单独控制一个的显示隐藏
<ul id="app">
 <li v-for='item in items' @click="toggle(item)">
  <span v-if='item.show'>{{item.content}}</span>
 </li>
</ul>

new Vue({
 el: '#app',
 data: function() {
  return {
   items: [{
    content: '1 item',
    show: true
   }, {
    content: '2 item',
    show: true
   }, {
    content: '3 item',
    show: true
   }]
  }
 },
 methods: {
  toggle: function(item) {
      item.show = !item.show;
  }
 }
})

vue点击元素input获取焦点
firstNameClick(){
  this.$nextTick(() =>{
    this.$refs.firstname.focus()
  })
},

<div @click="firstNameClick">
    <input type="text" ref="firstname">
</div>

Vue.nextTick()
当项目中你想在改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作都需要放进Vue.nextTick()的回调函数中;
Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。
  created(){
    let that=this;
    that.$nextTick(function(){  //不使用this.$nextTick()方法会报错
        that.$refs.aa.innerHTML="created中更改了按钮内容";  //写入到DOM元素
    });
  },

v-model.trim 将用户输入的前后的空格去掉