Vue基础

Vue特点:

  1. 采用组件化模式,提高代码复用率,且让代码更好维护
  2. 声明式编码,让编码人员无需重复操作DOM,提高开发效率
  3. 使用虚拟化DOM+优秀的Diff算法,尽量复用DOM节点

vue基本使用:

  1. 想让vue工作,就必须建立一个vue实例,并且要传入配置对象
  2. root容器中的代码遵循HTML语法规范,但其中有特殊的vue语法
  3. root容器中的代码称为【vue模板】
  4. vue实例和容器都是一一对应的
  5. 真实开发中只有一个vue实例,并配合组件一起使用
  6. {{xxx}}中xxx为 js 表达式,且xxx可以自动读取到data中的所有数据
  7. 一旦vue实例中data值改变,容器中对应位置的内容也会改变

在这里插入图片描述
例如下方,new关键字,就创建了一个vue实例,el和data就是当前实例的配置对象,此时新创建的vue对象就可以叫做vm对象

<!DOCTYPE html>
<html lang="en">

<head>
    <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h1>hello,{{name}}</h1>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
            // 创建vue实例
        new Vue({
            el: "#root", //el用于指定当前vue为那个容器服务
            data: { //data中存储数据
                name: '尚硅谷'
            }
        })
    </script>
</body>

</html>

vue模板语法

插值语法

在root容器中将要改变插入的值写在{{}}中,并把对应的值,写在vue实例中,想改变其中内容时,直接改变vue实例中的值就好了

<div id="root">
        <h1>插值语法</h1>
        <h3>你好,{{name}}</h3>
        <hr/>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false //组织vue在启动时生成生产提示
        new Vue({
            el: "#root",
            data: {
                name: 'qjj'
            }
        })
指令语法

指令一般都是v-后面跟上相应内容,表示vue中的指令,vue实例中的相应值,就会被应用到指令这里

<div id="root">
        <h1>指令语法</h1>
        <a v-bind:href="url">点我去学习</a>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false //组织vue在启动时生成生产提示
        new Vue({
            el: "#root",
            data: {
                url: "http://baidu.com"
            }
        })
    </script>

这里,v-bind:就是一个指令,在一般应用中,可以把v-bind:简化为:来使用,效果都只一样的

一般来说,当想把内容放置在标签体之中,一般使用插值语法,当想把内容放置在标签属性中,使用指令语法

vue数据绑定

数据绑定一共两种v-bind和v-model,两者之间的区别:
v-bind是单向绑定,只能通过修改vue实例中的数据,才能改变内容,直接修改页面内容,vue实例中的数据不会被修改
v-model则是双向绑定,不论修改页面内容或者vue实例中数据,vue实例中数据都会改变,双向绑定一般应用在表单类元素上(有value值)
一般,可以把v-model:value简化为v-model因为v-model默认就是收集的value值

el和data两种写法
el两种写法:

最常见的一种,就是将两个都写在vue实例中

new Vue({
    el:"#root",
    data:{
        name:"123"
    }
})

第二种,不在vue实例中写绑定容器,只写数据,将绑定容器放在vue实例外边,但是这个时候需要用变量接收vue实例,并使用vue中的方法v.$mount('')在引号中写入绑定容器

const v = new Vue({
    // el: "#root",
    data: {
        name: "尚硅谷"
    }
})
v.$mount('#root')
data两种写法:

第一种,对象式,将数据作为data对象属性,写在其中

data:{
    name:"123"
}

第二种,函数式,将data写作一个函数,函数必须要返回一个对象,其中有我们的数据,必须是普通函数,不能使用箭头函数

data:function(){
    return{
        name:"123"
    }
}
//更简单一种,两种效果一样
data(){
    return{
        name:"123"
    }
}

data函数中的this是vue,箭头函数没有自己的this,所以不提倡

数据代理(Object.defineProperty()

这个方法一般是用来想对象中添加属性,并且控制属性的相关操作,首先定义一个person对象:

let person = {
    name: '张三',
    sex: '男'
}

现在想向其中添加一个属性,年龄为18,可以直接在对象中添加,也可以使用Object.defineProperty()其中传入三个参数(添加对象,属性名,配置对象)

这种方法添加的属性:

  1. 一般不能够被遍历,需要加上enumerable:true
  2. 一般添加的属性的值不可以被修改, 需要加上writable: true
  3. 一般不能被删除,需要加上configurable:tru
Object.defineProperty('person', 'age', {
    value: 18,
    enumerable: true, //控制添加的属性可以被遍历
    writable: true, //控制添加的属性值可以被修改
    configurable: true //控制添加的属性可以被删除
})

但是如果这时的情况是,我们已经有了一个变量number,其中存储着年龄值,如何让添加进来的age属性等于number,并且可以随着number的改变而变化,下面是一个person对象和一个number变量

let number = 18
let person = {
    name: '张三',
    sex: '男'
}

可以用get函数和set函数共同来操作

get函数

当有人读取person的age属性时,get函数(getter)就会被调用,且返回值是age的值

get(){
    return number
}
set函数

当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的值

set(value){
     number = value
}

在这里插入图片描述

vue中的数据代理

通过vm对象来代理data对象中属性的操作,通过数据代理,可以更加方便的操作data中的数据

基本原理:

  • 通过Object.defineProperty()把data对象中所有属性添加到vm 上。
  • 为每一个添加到vm上的属性,都指定一个getter/setter。
  • 在getter/setter内部去操作,(读/写)data中相应属性

在这里插入图片描述

vue事件处理

事件的基本使用:
  1. 使用v-on:xxx或者@xxx绑定事件,其中xxx是事件名(例如点击,放置…)
  2. 事件的回调需要配置在methods对象中,最终会在vm上
  3. methods中配置的函数,不可以用箭头函数,否则this不是vm
  4. methods中配置的函数,都是被vue所管理的函数,this指向vm或组件实例对象
  5. @click="demo"@click="demo($event)"效果一致,但是后者可以传参
<script type="text/javascript">
     Vue.config.productionTip = false //组织vue在启动时生成生产提示
     new Vue({
         el: '#root',
         data: {
             name: '尚硅谷'
         },
         methods: {
             showInfo() {
                 alert('同学你好')
             }
         }
     })
 </script>
事件修饰符

vue中的事件修饰符:

  1. prevent:阻止默认事件
  2. stop:阻止事件冒泡
  3. once:事件只触发一次
  4. capture:是用事件的捕获模式
  5. self:只有event.target是当前操作的元素才触发事件
  6. passive:事件的默认行为立即执行,无需等待事件回调执行完毕

例如,当容器中是一个链接时,点击它弹窗后,但不想跳转,这时候就是阻止默认事件发生,使用时间修饰符prevent,如果一个事件,想用两个修饰符,可以连着使用

<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
    <a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //组织vue在启动时生成生产提示
    new Vue({
        el: '#root',
        data: {
            name: '尚硅谷'
        },
        methods: {
            showInfo() {
                alert('同学你好')
            }
        }
    })
</script>
阻止事件冒泡
<div class="demo" @click="showInfo">
    <button @click.stop="showInfo">点我提示信息</button>
</div>
键盘事件

vue中常用的案件别名:

  • 回车 ==> enter
  • 删除 ==> delete(捕获删除和退格键)
  • 退出 ==> esc
  • 空格 ==> space
  • 换行 ==> tab(必须配合keydown使用)
  • 上 ==> up
  • 下 ==> down
  • 左 ==> left
  • 右 ==> right
<div id="root">
    <h2>欢迎来到{{name}}</h2>
    <input type="text" placeholder="按下回车提示" @keyup.enter="showInfo">
</div>
<script type="text/javascript">
     Vue.config.productionTip = false //组织vue在启动时生成生产提示
     new Vue({
         el: '#root',
         data: {
             name: '尚硅谷'
         },
         methods: {
             showInfo(e) {
                 // if (e.keyCode !== 13) return
                 console.log(e.target.value);
             }
         }
     })
 </script>
系统修饰键(用法特殊):ctrl,alt,shift,meta
  1. 可以配合keyup使用,但是在使用时需要按下修饰键,同时按下其他键,然后再放开其他键,才能生效
  2. 配合keydown使用,正常触发事件

计算属性(computed)

要用的属性不存在,需要通过计算来得出
原理:底层借助了Object.defineProperty()提供的getter和setter
get函数执行时间:

  1. 初次读取读取时
  2. 当get依赖的内容发生变化会被再次调用

计算属性最终会出现在vm上,可以直接读取调用

<div id="root">
  姓:<input type="text" v-model="firstname"><br><br> 名:
    <input type="text" v-model="lastname"><br><br> 全名:
    <span>{{fullname}}</span>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //组织vue在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
            firstname: '张',
            lastname: '三'
        },
        computed: {
            fullname: {
                // 当有人读取fullname的值时,就会调用get
                // get调用时间:1.初次读取fullname时 2.get所依赖的内容发生变化
                get() { //此处的this时vm
                    return this.firstname + '-' + this.lastname
                },
                // 当fullname被修改时,会调用set
                set(value) {
                    const arr = value.split('-');
                    this.firstname = arr[0];
                    this.lastname = arr[1]
                }
            }
        }
    })
</script>

简写,当computed计算属性中,只使用get,不使用set时,可以简写

computed:{
    fullname(){
         return this.firstname + '-' + this.lastname
    }
}

监视属性(watch)

监视某一个属性变化,函数立即调用,一共两种写法

第一种
写在vue实例中,当在创建vue实例时就知道监视谁
watch: {
   ishot: {
        //当ishot发生改变时,调用
        handler(newvalue, oldvalue) {
            console.log('xiugai', newvalue, oldvalue);
        },
        immediate: true //立即执行,初始化时,让handler直接调用
    }
}

第二种
写在vue实例外,在创建过后才知道监视谁
vm.$watch('ishot', {
    immediate: true,
    handler(newvalue, oldvalue) {
        console.log('xiugai', newvalue, oldvalue);
    },
})
深度监视

vue中的watch自身默认不监视对象内部元素改变,监视多级结构中的属性变化

const vm = new Vue({
    el: '#root',
    data: {
        ishot: true,
        numbers: {
            a: 1,
            b: 2
        }
    },
    watch: {
        //监视多级结构中某个属性的变化
        'numbers.a': {
            handler() {
                console.log('改变了');
            }
        },
        //监视多级结构中所有属性的变化
        numbers: {
            deep: true,//深度监视
            handler() {
                console.log('改变了');
            }
        }
    }
})

简写,当监视属性中,不需要深度监视,和立即执行,只需要handler函数时,可以简写

也是一共两种
第一种,写在vue实例中
watch: {             
//简写
    ishot(newvalue, oldvalue) {
        console.log('xiugai', newvalue, oldvalue);
    }
}

第二种
写在vue实例外
vm.$watch('ishot', (newvalue, oldvalue) {
   console.log('xiugai', newvalue, oldvalue);
})
计算属性和监视属性对比
  1. computed能完成的功能,watch都能完成
  2. watch能完成的功能,computed不一定都能完成(watch可实现异步操作)

注意

  1. 所有被vue管理的函数都写成普通函数
  2. 所有不被vue管理的函数,最好写成箭头函数

绑定样式

一共常见的就三种,在需要情况不同时,采用不同的写法

<div id="root">
   <!-- 字符串写法,当样式的类名不确定,需要动态指定时 -->
    <div class="basic" :class="mood" @click="change">{{name}}</div>

    <!-- 数组写法,要绑定的样式个数不确定,名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div>

    <!-- 对象写法,当绑定的样式个数和名字都确定,但需要动态决定要不要时 -->
    <div class="basic" :class="classObj">{{name}}</div>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //组织vue在启动时生成生产提示
    new Vue({
        el: "#root",
        data: {
            name: '尚硅谷',
            mood: 'normal',
            classArr: ['class1', 'class2', 'class3'],
            classObj: {
                class1: false,
                class2: false
            }
        },
        methods: {
            change() {
                this.mood = "sad"
            }
        },
    })
</script>

条件渲染

分别使用v-show和v-if来做条件渲染,v-show只是隐藏,但改项目还在,v-if直接去掉该内容

<div id="root">
    <!-- v-show做条件渲染 -->
    <h2 v-show="false">欢迎来到{{name}}</h2>

    <!-- v-if做条件渲染 -->
    <h2 v-if="false">欢迎来到{{name}}</h2>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //组织vue在启动时生成生产提示
    new Vue({
        el: '#root',
        data: {
            name: '尚硅谷'
        }
    })
</script>

在使用v-if时,v-else-if和v-else同时也可以使用,判断的逻辑和js中一样,在使用v-else-if和v-else之前,必须要有v-if,且不能打断,必须要连在一起
注:使用v-if时元素可能无法获取到

列表渲染

一个简单的列表,在vue中,使用v-for来进行循环列表渲染,每一个标签都需要有自己的“key”
语法:v-for="(item, index) in xxx" :key="yyy"

<div id="root">
  <!-- 遍历数组 -->
    <h2>人员列表</h2>
    <ul>
        <li v-for="(p,index) in persons" :key="p.id">{{p.name}}-{{p.age}}</li>
    </ul>

    <!-- 遍历对象 -->
    <h2>汽车信息</h2>
    <ul>
        <li v-for="(c,key) in car" :key="key">{{key}}-{{c}}</li>
    </ul>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false //组织vue在启动时生成生产提示
    new Vue({
        el: '#root',
        data: {
            persons: [{
                id: '001',
                name: '张三',
                age: 18
            }, {
                id: '002',
                name: '李四',
                age: 19
            }, {
                id: '003',
                name: '王五',
                age: 20
            }, ],
            car: {
                name: '奥迪',
                price: '100',
                color: 'red'
            }
        }
    })
</script>

key
key的作用:key是虚拟DOM对象的标识,当状态中的数据发生变化时, Vue会根据【新数据】生成【新的虚拟DON】
,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较 对比规则:

  1. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
    1.若虚拟DOM中内容没变,直接使用之前的真实DOM !
    2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉 页面中之前的真实DOM.
  2. 旧虚拟DOM中未找到与新虚拟DOM相同的key,创建新的真实DOM,随后渲染到到页面。

用index作为key的问题:

  1. 若对数据进行逆序添加,逆序删除等破坏原本排列顺序的操作时,会产生没有必要的真是DOM更新(效率低下)
  2. 如果结构中还包含输入类的DOM,则界面会产生问题,当进行逆序添加,逆序删除时

vue监测数据原理

vue会监视data中所有层次的数据
如何监测对象中的数据:通过setter去实现监测,且在new vue时就需要传入需要监测的数据

  1. 对象中后追加的属性默认不做响应式处理
  2. 如需给后添加的属性做响应式,需要使用Vue.set(target,name,value)或者 this.$set(target,name,value)

如何监测数组中的数据:通过包裹数组更新元素的方法实现,本质做了两件事

  1. 调用原生对应的方法对数组进行更新
  2. 重新解析模板,进而更新页面

vue修改数组中某元素:

  1. API:push(), pop(), shift(), unshift(), splice(), sort(), recerse()
  2. 方法:vue.set()和vm.$set(),不可以给vm或者vm的根数据对象添加属性
  3. filter(), concat(), slice()不会改变原数组,只会返回新数组

收集表单数据

类型为<input type="text"/>,则v-model收集的是value值,也就是用户输入
类型为<input type="radio"/>,则v-model收集的是value值,且要给每个标签都配置value值
类型为<input type="checkbox"/>

  • input没有配置value属性,v-model收集的就是checked(true 或者 false)
  • input配置了value属性:
    1)v-model的初始值为非数组,则收集到的仍是(true 或者 false)
    2)v-model的初始值为数组,则收集到的就是由value组成的数组

v-model三个修饰符:

  • lazy:失去焦点再收集数据
  • number:将输入的字符串中的数字,转化为number存储
  • trim:省略收尾空格

内置指令:

之前见到过的:

  1. v-bind单向绑定解析表达式,可简写为:xxx
  2. v-model双向数据绑定
  3. v-for遍历数组,对象,字符串
  4. v-on绑定事件监听,可简写为@
  5. v-if条件渲染(动态控制节点是否存在)
  6. v-else条件渲染(动态控制节点是否存在)
  7. v-show条件渲染(动态控制节点是否展示)

学习:

  1. v-text:向所在节点中渲染文本内容,v-text会直接替换掉节点中所有内容,{{xx}}插值语法不会(不支持html结构解析)
  2. v-html用法与v-text相同,但他支持html结构解析(但是,v-html有安全性问题)
  3. v-cloak没有值,本质是配合css解决网速慢时页面展示出未被渲染的内容
  4. v-once没有值,所在节点在初次动态渲染后,就视为静态内容,以后数据的变化,不会影响该节点数据变化
  5. v-pre跳过所在节点的编译过程,在不使用vue实例中内容的节点可以加

自定义指令

调用时间:1.指令与元素成功绑定(一开始)2.指令所在的模板被重新解析时
定义:
1.局部指令

1)
new Vue({
    directives: {指令名:配置对象}
})

2)
new Vue({
    directives{指令名:回调函数}
})

2.全局指令

1)
Vue.directive(指令名,配置对象)

2)
Vue.directive(指令名,回调函数)

示例:

//函数式
big(element, binging) {
  element.innerText = binging.value * 10
},
//对象式
fbind: {
    // 指令与元素成功绑定(一开始)
    bind(element, binging) {
        element.value = binging.value
    },
    // 指令所在元素被插入页面时
    inserted(element, binging) {
        element.focus()
    },
    // 指令所在模板被重新解析时
    update(element, binging) {
        element.value = binging.value

    }
}
配置对象中三个回调:
  1. bind指令与元素成功绑定时调用
  2. inserted指令所在元素被插入页面时调用
  3. update指令所在模板被重新解析时调用

注:定义指令不加v-,使用指令时要加v-

生命周期

又叫生命周期回调函数,生命回调函数,生命周期钩子,函数内部的this指向时vm或者组件实例对象

  • 将要创建,调用beforecreate函数
  • 创建完毕,调用create函数
  • 将要挂载,调用beforemounted函数
  • 挂载完毕,调用mounted函数,发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
  • 将要更新,调用beforeupdate函数
  • 更新完毕,调用update函数
  • 将要销毁,调用beforedestroy函数,清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
  • 销毁完毕,调用destroy函数