1、Vue基础学习

本文详细介绍了Vue.js的基础知识,包括Vue的渐进式特性、MVVM模型、数据代理、事件处理、计算属性和监听。讨论了如何使用Vue创建用户界面,数据绑定,以及如何响应数据变化。同时,提到了Vue中的条件渲染、列表渲染、计算属性和监听数据变化的原理。
摘要由CSDN通过智能技术生成
文章目录

1、Vue简介

2、基本使用

3、理解MVVM模型

4、数据代理

5、事件

6、计算属性

7、监听

8、绑定样式

9、列表

10、监测数据的原理

11、收集表单数据

12、过滤器

13、指令

14、生命周期

一、Vue简介

1、定义

官网定义:

一套用于构建用户界面的渐进式JavaScript库

构建用户界面:拿到的数据,通过某种办法,变成用户可看见的界面

前端的职责:在合适的时机发送合适请求,把得到的响应数据展示在合适的位置

渐进式:Vue可以自底向上逐层的应用,即

简单应用:只需一个轻量小巧的核心库(100kb)

复杂应用:可以引入各式各样的Vue插件

作者:尤雨溪

2、特点

  • 采用组件化模式,提高代码复用率,且让代码更好的维护
  • 声明式编码,让编码人员无需直接操作dom,提高开发效率
  • 使用虚拟dom+优秀的diff算法,尽量复用dom节点

ES6语法规范、ES6模块化、包管理器、原型/原型链、数组常用方法、axios、promise…

二、基本使用

官网:cn.vuejs.org

直接script引入

1、初始Vue

  • 让Vue 工作,必须先创建一个Vue实例,且要传入一个配置对象{ el: ‘#root’, data: {} }
  • root容器里的代码依然符合html规范,只不过混入一些特殊的Vue语法
  • root容器里的代码,被称为【Vue模板】
  • Vue实例和容器是一一对应的
  • 真实开发中只有一个Vue实例,并且配合组件一起使用
  • {{XXX}}中的XXX是表达式,且XXX可以自动读取到data中的所有属性值
  • 一旦data中的数据发生改变,模板(页面)中用到该数据的地方也会自动更新
<html>
    ......
    <body>
        <div id="root">
            <h1>
                hello, {{name}}
            </h1>
        </div>
        <script type="text/javascript">
            Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
            
            // 创建Vue实例
            new Vue({
                el: '#root', // 用于指定当前Vue实例为哪个容器服务,值通常为css值选择器字符串
                data: { // 用于存储数据,数据供el所指定的容器去使用
                    name: 'cyr'
                }
            })
            
            // 容器和实例,一一对应
        </script>
    </body>
</html>

注意区分: js表达式 和 js代码(语句)

  1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方

    例:a、a + b、demo(1)、x === y ? ‘a’ : ‘b’

  2. js代码(语句)

    例:if(){}、for(){}

2、模板语法

  • 插值语法(解析标签体内容)

    {{表达式}}

  • 指令语法(解析标签:标签属性、标签体内容、绑定事件)

    v-bind(:)、v-model、v-on(@)、v-if、v-else、v-for、v-show

3、数据绑定

v-bind 单向数据绑定(数据只能从data流向页面)

v-model 双向数据绑定(数据不仅能从data流向页面,也能从页面流向data),只能应用在表单类元素(输入类元素)

其中,v-model:value可简写为v-model,因v-model默认收集的就是value值

4、_el与data的两种写法

<html>
    ......
    <body>
        <div id="root">
            <h1>
                hello, {{name}}
            </h1>
        </div>
        <script type="text/javascript">
            Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
            // el的两种写法
            // 方法一
            // 创建Vue实例到对应的容器
            new Vue({
                el: '#root'
                data: {
                    name: 'cyr'
                }
            })  
            // 方法二
            // 创建Vue实例
            const v = new Vue({
                data: {
                    name: 'cyr'
                }
            })
            console.log(v)
            // 挂载到对应的容器
            v.$mount('#root')
            
            // data的两种写法
            new Vue({
                el: '#root',
                // 第一种写法:对象式
                data: {
                    name: 'cyr'
                },
                // 第二种写法:函数式
                // 不可使用箭头函数,不然this就是指向Window
                // data: function() {
                data() {
                    console.log('此处的实例式Vue实例对象', this)
                    return {
                        name: 'cyr'
                    }
                }
            })
        </script>
    </body>
</html>

三、理解MVVM模型

1、M

模型Model => 对应data中的数据

2、V

视图View => 模板

3、VM

视图模型ViewModel => Vue实例对象

4、关系

​ VM

M --数据绑定(Data Bindings)–> V

V --数据建通(Dom Listeners)–> M

四、数据代理

1、回顾Object.defineProperty

给对象添加属性

let num = 18
const person = {
    name: 'cyr',
    sex: '女',
    // age: 18
}

Object.defineProperty(person, 'age', {
    // value: 18,
    // enumerable: true // 控制属性是否可枚举(遍历),默认值是false
    // writable: true // 属性是否可被修改,默认值是false
    // configuable: true // 属性是否可被删除,默认值是false
    
    // 当有人读取person的age属性时,get函数(getter)会被调用,且返回值就是get的值
    get: function(){
        console.log('有人读取age属性的值')
        return num
    },
    // 当有人修改person的age属性时,set函数(setter)会被调用,且会收到修改的具体值
    set: function(value){
        console.log('有人修改age属性的值', value)
        num = value
    }
})

console.log(Object.keys(person))

2、理解数据代理

通过一个对象代理另一个对象中属性的操作

let obj = { x: 1}
let obj2 = { y: 2 }

Object.defineProperty(obj2, 'x', {
    get() {
        return obj.x
    },
    set(value) {
        obj.x = value
    }
})

3、Vue的数据代理

  1. 通过vm对象来代理data对象中属性值的操作(读/写)

  2. 更加方便的操作data中的数据

  3. 基本原理:

    通过Object.defineProperty()把data对象中所有的属性添加到vm上

    为每一个添加到vm上的属性,都指定一个getter/setter

    在getter/setter内部去操作(读/写)data中对应的属性

其中,vm._data是定义Vue实例的options.data

五、事件

1、事件处理

基本使用

  • 使用v-on:XXX或@XXX绑定事件,其中XXX是事件名称
  • 事件的回调需要配置在methods对象上,最终会在vm上
  • methods上配置的函数,不要用箭头函数,否则this就不是vm
  • methods上配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对
  • @click=“demo” 和 @click=“demo($event)” 效果一样,但后者可以传参
<html>
    ...
    <body>
        <div id="root">
            <h2>
                欢迎来到{{name}}的vue学习
            </h2>
            <button @click="showinfo1">
                点我提示信息1(不传参)
            </button>
            <button @click="showinfo2($event, 66)">
                点我提示信息2(传参)
            </button>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                name: 'cyr'
            },
            methods: {
                showInfo1(event) {
                    console.log(event.target.innerText)
                    console.log(this, this === vm)
                    alert('你好')
                },
                showInfo: (event) => {
                    console.log(this, this === Window)
                },
                showInfo2(event, number) {
                    console.log(event.target.innerText)
                    console.log(this, this === vm)
                    console.log(event, number)
                    alert('你好' + number)
                }
            }
        })
    </script>
</html>

2、事件的修饰符

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

3、键盘事件

  • 常用的按键别名:回车enter、删除delete、退出esc、空格space、换行tab、上up、下down、左left、右right

  • Vue未提供别名的按键,可以使用按键最原始的key值去绑定,但注意要转为kebab-case(短横线命名)

  • 系统修饰键(用法特殊):ctrl、alt、shift、meta

    配合keyup使用:按下修饰键的同时,再按下其他键,事件才会被触发

    配合keydown使用:正常触发事件

  • 也可以使用keyCode去指定具体按键(不推荐)

  • Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名

六、计算属性

1、计算属性:computed

  • 定义:要用的属性不存在,要通过已有属性计算得来的

  • 原理:底层借助了Object.defineproperty方法提供的getter和setter

  • get方法什么时候执行?1、初读时会执行一次 2、所依赖的数据发生变化时

  • 优势:比methods实现相比,内部有缓存机制(复用),效率更高,调试更方便

  • 备注:

    1、计算属性最终会出现在vm上,直接读取使用即可。

    2、如果计算属性要被修改,那必须写set函数去响应修改,且set函数要引起计算时所依赖的数据发生变化

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '陈',
        lastName: '三'
    },
    // 计算属性
    computed: {
        // 完整写法
        fullName: {
            // 当有人读取时,get就会被调用,且返回值就作为fullName的值
            // get什么时候调用?1、初次读取fullName时(有缓存) 2、所依赖的数据发生变化
            get() {
                // console.log(this) // 此处的this是vm
                return this.firstName + '/' + this.lastName
            },
            // set什么时候调用?当fullName被修改时
            set(val) {
                const [this.firstName, lastName] = val.split('/')
            }
        }
        // 简写(只用get, 不用set)
        fullName11(){
             // console.log(this) // 此处的this是vm
             return this.firstName + '/' + this.lastName
        }
    }
})

2、同methods的区别

计算属性computed是有缓存的,只有初次读取的时候或所依赖的数据发生变化时,才会去调用get方法

方法methods是只要页面引用多少次,就会被调用多少次

七、监听

1、监听:watch

  • 当被监视的属性变化时,回调函数自动调用,进行相关操作

  • 监视的属性必须存在,才能进行监视

  • 监视的两种写法

    1、new Vue传入watch配置

    2、通过vm.$watch监视

const vm = new Vue({
    el: '#root',
    data: {
        isHot: true,
        isHot1: true,
        numbers: {
            a: 1,
            b: 2
        }
    },
    watch: {
        // 正常写法
        isHot: {
            immediate: true, // 初始化时让handler调用下 
            // handler什么时候调用?当isHot发生变化时
            handler(newVal, oldVal) {
                console.log('isHot被修改了', newVal, oldVal)
            }
        },
        // 简写写法
        isHot1(newVal, oldVal) {
            console.log('isHot1被修改了', newVal, oldVal)
        },
        // 监视多级结构中某个属性的变化
        'numbers.a': {
            immediate: true, // 初始化时让handler调用下 
            // handler什么时候调用?当isHot发生变化时
            handler(newVal, oldVal) {
                console.log('isHot被修改了', newVal, oldVal)
            }
        },
        // 监视多级结构中所有属性的变化
        numbers: {
            deep: true, // 开启深度监视 
            // handler什么时候调用?当isHot发生变化时
            handler(newVal, oldVal) {
                console.log('isHot被修改了', newVal, oldVal)
            }
        }
    }
})
// 也可以用实例来进行监视
// 正常写法
vm.$watch('isHot', {
    immediate: true, // 初始化时让handler调用下 
        // handler什么时候调用?当isHot发生变化时
        handler(newVal, oldVal) {
        console.log('isHot被修改了', newVal, oldVal)
     }
})
// 简写写法
vm.$watch('isHot1', function (newVal, oldVal) {
     console.log('isHot被修改了', newVal, oldVal)
})

2、深度监听

  • Vue中的watch默认不监测对象内部值的改变(一层)

  • 配置deep: true可以监测对象内部值改变(多层)

  • 备注:

    1、Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以

    2、使用watch时根据数据的具体结构,决定是否采用深度监听

3、watch对比computed

  • computed能完成的功能,watch都可以完成

  • watch能完成的功能,computed不一定能完成。例如watch可以进行异步操作

  • 两个重要小原则:

    1、所被Vue管理的函数,最好写成普通函数,这样this指向才是vm 或 组件实例对象

    2、所有不被Vue管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数等),最好写成箭头函数,这样this的指向才时 vm 或 组件实例对象

八、绑定样式

1、绑定class样式

  • :calss=‘xxx’
  • 表达式是字符串:‘classA’
  • 表达式是对象:{classA: true, classB: false}
  • 表达式是数组:[‘calssA’, 'classB ']

2、绑定style样式

  • :style=‘xxx’
  • 表达式是字符串:‘font-size: 16px; color: red;’
  • 表达式是对象:{fontSize: ‘16px’, color: red}
  • 表达式是数组:[{fontSize: ‘16px’, color: red}, {backgroundColor: gray}]

九、列表

1、条件渲染

v-show

值:true/false

dom节点存在,调整样式display:none

v-if/v-else-if/v-else

值:true/false

不展示dom节点,直接被移除掉

切换频率大的话,建议使用v-show

2、列表渲染

<html>
    ...
    <body>
        <div id="root">
            <!--  遍历数组 -->
            <h2>人员列表</h2>
            <ul>
                <li v-for="(p, index) of persons" :key="index">
                    {{p.name}}-{{p.age}}
                </li>
            </ul>
            <!--  遍历对象 -->
            <h2>汽车信息</h2>
            <ul>
                <li v-for="(val, k) of car" :key="k">
                    {{k}}-{{val}}
                </li>
            </ul>
            <!--  遍历字符串 -->
            <h2>测试遍历字符串</h2>
            <ul>
                <li v-for="(char, index) of str" :key="index">
                    {{char}}-{{index}}
                </li>
            </ul>
            <!--  遍历指定次数 -->
            <h2>测试遍历指定次数</h2>
            <ul>
                <li v-for="(number, index) of 5" :key="index">
                    {{number}}-{{index}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ],
                car: {
                    name: '奥迪'price: '10万'
                },
                str: 'hello'
            }
        })
    </script>
</html>

key的作用和原理(面试题:react、vue的key有什么作用?)–给节点做标识,就像人类的身份证

  1. 虚拟dom中key的作用:

    key是虚拟dom对象的标识,当状态中的数据发生改变时,Vue会根据【新数据】生成【新的虚拟dom】,随后Vue进行【新的虚拟dom】的差异比较

  2. 差异对比规则:

    • 旧虚拟dom中找到了与新虚拟dom相同的key
      1. 若虚拟dom中的内容没改变,直接使用之前的真实dom
      2. 若虚拟dom中的内容发生改变,则生成新的真实dom,随后替换页面中之前的真实dom
    • 旧虚拟dom中未找到与新虚拟dom相同的key
      1. 创建新的真实dom,随后渲染到页面
  3. 用index作为key可能会引发的问题

    • 若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实dom更新(页面效果没问题,但是效率低)
    • 如果结构中还包含输入类的dom,会产生错误的dom更新(界面有问题)
  4. 开发中如何选择key

    • 最好使用每条数据的唯一标识作为key,比如id、手机号等唯一值
    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表作于展示,使用index作为key是没有问题

3、列表过滤

<html>
    ...
    <body>
        <div id="root">
            <h2>人员列表</h2>
            <input type="text" placeholder="请输入名字" v-model="keyWord" />
            <ul>
                <li v-for="(p, index) of filPersons" :key="index">
                    {{p.name}}-{{p.age}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        // 用watch实现
        const vm = new Vue({
            el: '#root',
            data: {
                keyWord: '',
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ],
                filPersons: []
            },
            watch: {
                keyWord: {
                    handler(val) {
                        immediate: true,
                        this.filPerson = this.persons.filter(e => {
                            return e.name.indexOf(val) !== 1
                        })
                    }
                }
            }
        })
        // 用computed实现
        const vm1 = new Vue({
            el: '#root',
            data: {
                keyWord: '',
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ]
            },
            computed: {
                filPersons(){
                    return this.persons.filter(e => {
                        return e.name.indexOf(this.keyWord) !== 1
                    })
                }
            }
        })
    </script>
</html>

4、列表排序

<html>
    ...
    <body>
        <div id="root">
            <h2>人员列表</h2>
            <input type="text" placeholder="请输入名字" v-model="keyWord" />
            <button @click="sortType = 2">年龄升序</button>
            <button @click="sortType = 1">年龄降序</button>
            <button @click="sortType = 0">原顺序</button>
            <ul>
                <li v-for="(p, index) of filPersons" :key="index">
                    {{p.name}}-{{p.age}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                sortType: 0, // 0:原顺序 1:降序 2:升序
                keyWord: '',
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ]
            },
            computed: {
                filPersons(){
                    consr arr = this.persons.filter(e => {
                        return e.name.indexOf(this.keyWord) !== 1
                    })
                    if (this.sortType) {
                        arr.sort((p1, p2) => {
                           return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                        })
                    }
                    return arr
                }
            }
        })
    </script>
</html>

十、监测数据的原理

1、监测对象的原理

<html>
    ...
    <body>
        <div id="root">
            <h2>人员列表</h2>
            <button @click="updateFirstInfo">
                点击修改第一条信息
            </button>
            <ul>
                <li v-for="(p, index) of persons" :key="p.id">
                    {{p.name}}-{{p.age}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ]
            },
            methods: {
                updateFirstInfo() {
                    // 有效更改
                    this.persons[0].name = 'test'
                    this.persons[0].age = 21
                    // 无效更改(Vue无法识别到更改,并响应到页面)
                    this.persons[0] = {id:'0001', name: 'test', age: 21}
                }
            }
        })
    </script>
</html>

原理理解:

let data = {
    name: 'cyr',
    address: '上海'
}

// 创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
// 准备一个vm实例对象
const vm ={}
vm._data = data = obs

function Observer(obj) {
    // 汇总对象中所有的属性形成一个数组
    const keys = Object.keys(obj)
    // 遍历
    keys.forEach((k) => {
        Object.defineProperty(this, k, {
            get() {
                return obj[k]
            },
            set(val) {
                console.log(`${k}被改了,我要去解析模板,生成虚拟dom,进行比较,生成真实dom,渲染页面......`)
                obj[k] = val
            }
        })
    })
}

2、_Vue.Set()方法

<html>
    ...
    <body>
        <div  id="root">
            <h2>人员列表</h2>
            <button @click="addSex">
                添加性别信息
            </button>
            <h5>
                姓名: {{personInfo.name}}
            </h5>
            <h5>
                年龄: {{personInfo.age}}
            </h5>
             <h5 v-if="personInfo.sex">
                性别: {{personInfo.sex}}
            </h5>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                personInfo:{
                    id:'0001', 
                    name: 'cyr', 
                    age: 18
                }
            },
            methods: {
                addSex() {
                    // 无效更改(Vue无法识别到更改,并响应到页面)
                    this.personInfo.sex = '女'
                    vm._data.personInfo.sex = '女'
                    // 有效更改
                    this.$set(this.personInfo, 'sex', '女')
                }
            }
        })
        
        vm.$set === Vue.set
    </script>
</html>

3、监测数组的原理

<html>
    ...
    <body>
        <div id="root">
            <h2>人员列表</h2>
            <button @click="updateFirstInfo">
                点击修改第一条信息
            </button>
            <ul>
                <li v-for="(p, index) of persons" :key="p.id">
                    {{p.name}}-{{p.age}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                persons:[
                    {id:'0001', name: 'cyr', age: 18},
                    {id:'0002', name: 'll', age: 19},
                    {id:'0003', name: 'yy', age: 20}
                ]
            },
            methods: {
                updateFirstInfo() {
                    this.persons[0].splice(0, 1, {id:'0001', name: 'test', age: 21})
                    this.$set(this.persons, 0, {id:'0001', name: 'test', age: 21})
                }
            }
        })
    </script>
</html>

修改数组的方法(7个)

push()、pop()、shift()、unshift()、splice()、sort()、reverse()

只能操作这几个方法,才能监测数组的变化

Vue包装了这几个方法,来响应更新视图

4、总结

  • vue会监视data中所有层次的数据

  • 如何监测对象中的数据?

    通过setter实现监视,且要在new Vue时就传入要监测的数据

    1. 对象后追加的属性,Vue默认不做响应式处理
    2. 如需给后添加的属性做响应式,请使用如下API:Vue.set(target, propertyName/index, value)Vm.$set(target, propertyName/index, value)
  • 如何监测数组中的数据?

    通过包裹数组更新元素的方法实现,本质就是做了两件事

    1. 调用原生对应的方法对数组进行更新
    2. 重新解析模板,进而更新页面
  • 在vue修改数组中的某个元素一定要用如下方法:

    1. 使用这些API:push()/pop()/shift()/unshift()/splice()/sort()/reverse()
    2. Vue.set()vm.$set()
  • 特别注意:Vue.set()vm.$set()不能给vm或vm的跟数据对象,添加属性

十一、收集表单数据

<html>
    ...
    <body>
        <div id="root">
            <form @submit.prevent="submit">
                <label for="acount">账号</label>
                <input type="text" id="acount" v-model.trim="userInfo.account" />
                <br/><br/>
                <label for="password">密码</label>
                <input type="password" id="password" v-model="userInfo.password" />
                <br/><br/>
                <label for="age">年龄</label>
                <input type="number" id="age" v-model.number="userInfo.age" />
                <br/><br/>
                <label for="sex">性别</label><input type="radio" name="sex" id="sex" value="male" v-model="userInfo.sex" /><input type="radio" name="sex" id="sex" value="female" v-model="userInfo.sex" />
                <br/><br/>
                <label for="hoby">爱好</label>
                学习<input type="checkbox" name="hoby" id="hoby" value="study" v-model="userInfo.hoby" />
                打游戏<input type="checkbox" name="hoby" id="hoby" value="game" v-model="userInfo.hoby" />
                吃饭<input type="checkbox" name="hoby" id="hoby" value="eat" v-model="userInfo.hoby" />
                <br/><br/>
                <label for="city">所属校区</label>
                <select v-model="userInfo.city">
                    <option value="">请选择</option>
                    <option value="beijing">北京</option>
                    <option value="shanghai">上海</option>
                    <option value="shenzheng">深圳</option>
                </select>
                <br/><br/>
                <label for="other">其他信息</label>
                <textarea id="other" v-model.lazy="userInfo.other" />
                <br/><br/>
                <input type="checkbox" v-model="userInfo.agree" />
                阅读并接受<a href="https://baidun.com/">《用户协议》</a>
                <br/><br/>
                <button>提交</button>
            </form>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                userInfo: {
                    account: '',
                	password: '',
                    age: '',
                	sex: 'female',
                	hoby: [], // 多组勾选框,初始值必须为数组,不然后续的值是只有true/false的布尔型
                	city: '',
               		other: '',
                	agree: ''
                }
                
            },
            methods: {
                submit() {
                    console.log(JSON.stringfy(this.userInfo))
                }
            }
        })
    </script>
</html>
  • <input type='text' />,则v-model收集的是value值,用户输入的就是value值
  • <input type='radio' />,则v-model收集的是value值,且要给标签配置value值
  • <input type='checkbox' />
    1. 没有配置input的value值,那么收集的就是checked(勾选 or 未勾选,布尔值)
    2. 配置input的value属性:
      • v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,布尔值)
      • v-model的初始值是数组,那么收集的就是value组成的数组
  • 备注:v-model的三个修饰符
    1. lazy:失去焦点再收集数据
    2. number:输入字符串转为有效数字
    3. trim:输入首尾空格过滤

十二、过滤器

<html>
    ...
    <body>
        <div id="root">
            <h2>显示格式化后的时间</h2>
            <h3>现在是(时间戳): {{time}}</h3>
            <h3>现在是(计算属性实现): {{fmtTime}}</h3>
            <h3>现在是(methods实现): {{getFmtTime()}}</h3>
            <h3>现在是(过滤器实现): {{time | timeFormat}}</h3>
            <h3>现在是(过滤器实现+传参): {{time | timeFormat('YYYY年MM月DD日')}}</h3>
            <h3>现在是(过滤器实现+传参+多个): {{time | timeFormat('YYYY年MM月DD日') | mySlice}}</h3>
            <h3 :x="name | mySlice">dom属性加过滤器</h3>
        </div>
    </body>
    <script type="text/javascript" src='../js/dayjs.min.js'></script>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        // 全局过滤器
        Vue.filter('mySliceAll', function(value) {
            return value.slice(0, 5)
        })
        
        const vm = new Vue({
            el: '#root',
            data: {
                time: 1685455602818,
                name: 'hello word'
            },
            computed: {
                fmtTime() {
                    return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            methods: {
                getFmtTime() {
                    return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            // 局部过滤器
            filters: {
                // 第一个参数永远是传入值,再跟上模板里定义的参数
                timeFormat(value, str = 'YYYY-MM-DD HH:mm:ss') {
                    // console.log('@', value)
                    return dayjs(value).format(str)
                },
                mySlice(value) {
                    return value.slice(0, 5)
                }
            }
        })
    </script>
</html>

1、定义

对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)

2、语法

  • 注册过滤器:Vue.filter(name, callback) 或 new Vue({filters: {}})
  • 使用过滤器: {{ xxx | 过滤器名}} 或 v-bind:属性 = " xxx | 过滤器名"

3、备注

  • 过滤器也可以接收额外参数,多个过滤器也可以串联
  • 并没有哦改变原本的数据,是产生新的对应数据

十三、指令

1、回顾

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

2、v-text

  • 作用:向其所在的节点渲染文本内容
  • 与插值语法的区别:v-text会替换掉节点中的内容, {{xx}}则不会

3、v-html

  • 作用:向指定节点中渲染包含html结构的内容
  • 与插值语法的区别:
    1. v-html会替换掉节点中的内容, {{xx}}则不会
    2. v-html可以识别html结构
  • 严重注意:v-html有安全性问题
    1. 在网站上动态渲染HTML是非常危险的,容易导致XSS攻击,冒充用户的身份(如:document.cookie可以获取到当前用户的登录凭证)
    2. 一定要在可信的内容上使用v-html,不要在用户提交的内容上

4、v-cloak

  • 本身是没有值的
  • 本质是一个特殊属性,Vue创建完毕并接管容器后,会删掉v-cloak属性
  • 使用css配合v-cloak可以解决网速慢时,页面展示出{{xxx}}的问题

5、v-once

  • 本身是没有值的
  • v-once所在节点在初次动态渲染后,就视为静态内容了
  • 以后数据的改变不会引起v-once所在结构的更新,可用于优化性能

6、v-pre

  • 跳过其所在节点的编译过程
  • 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译

7、自定义指令

(1)函数式
<html>
    ...
    <body>
        <div id="root">
            <h2>当前的n值:<span v-text="n"></span></h2>
            <h2>放大十倍后的n值:<span v-big="n"></span></h2>
            <h2>放大十倍后的n值1:<span v-big-number="n"></span></h2>
            <button @click="n++">
                点我n+1
            </button>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        // 全局指令写法
        Vue.directive('big-all', function(element, binding){
            console.log('big', this) // this是指向window
            console.dir(element)
            console.log(element instanceof HTMLElement)
            console.log(element, binding.value)
            element.innerText = binding.value*10
        })
        
        const vm = new Vue({
            el: '#root',
            data: {
                n: 1
            },
            // 局部指令
            directives: {
                // 何时会被调用:1、指令与函数成功绑定时。2、指令所在的模板被重新解析时
                big(element, binding){
                    console.log('big', this) // this是指向window
                    console.dir(element)
                    console.log(element instanceof HTMLElement)
                    console.log(element, binding.value)
                    element.innerText = binding.value*10
                },
                'big-number'(element, binding){
                    console.dir(element)
                    console.log(element instanceof HTMLElement)
                    console.log(element, binding.value)
                    element.innerText = binding.value*10
                },
            }
        })
    </script>
</html>
(2)对象式
<html>
    ...
    <body>
        <div id="root">
            <h2>当前的n值:<span v-text="n"></span></h2>
            <h2>放大十倍后的n值:<span v-big="n"></span></h2>
            <h2>放大十倍后的n值1:<span v-big-number="n"></span></h2>
            <button @click="n++">点我n+1</button>
            <hr/>
            <input type='text' v-fbind:value="n" />
        </div>   
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示
        // 全局指令写法
        Vue.directive('fbind-all', {
            // 指令与函数成功绑定时
            bind(element, binding){
                console.log('bind')
                element.value = binding.value
            },
            // 指令所在的元素被插入页面时
            inserted(element, binding){
                console.log('inserted')
                element.focus()
            },
            // 指令所在的模板被重新解析时
            update(element, binding) {
                element.value = binding.value
            }
        })
        
        const vm = new Vue({
            el: '#root',
            data: {
                n: 1
            },
            // 局部指令
            directives: {
                // 何时会被调用:1、指令与函数成功绑定时。2、指令所在的模板被重新解析时
                big(element, binding){
                    console.log('big', this) // this是指向window
                    console.dir(element)
                    console.log(element instanceof HTMLElement)
                    console.log(element, binding.value)
                    element.innerText = binding.value*10
                },
                'big-number'(element, binding){
                    console.dir(element)
                    console.log(element instanceof HTMLElement)
                    console.log(element, binding.value)
                    element.innerText = binding.value*10
                },
                // fbind(element, binding) {
                //     element.value = binding.value
                //     // 初始化,无法实现聚焦,因其真实dom还未渲染到页面
                //     element.focus()
                // }
                fbind: {
                    // 指令与函数成功绑定时
                    bind(element, binding){
                        console.log('bind')
                        element.value = binding.value
                    },
                    // 指令所在的元素被插入页面时
                    inserted(element, binding){
                        console.log('inserted')
                        element.focus()
                    },
                    // 指令所在的模板被重新解析时
                    update(element, binding) {
                        element.value = binding.value
                    }
                }
            }
        })
    </script>
</html>
(3)总结
  • 定义语法:
    1. 局部指令:new Vue({ directives: {指令名: 配置对象} 或 directives: {指令名: 回调函数} })
    2. 全局指令:Vue.directives(指令名, 配置对象)Vue.directives(指令名, 回调函数)
  • 配置对象中常用的3个回调:
    1. bind:指令与元素成功绑定时调用
    2. inserted:指令所在元素被插入页面时调用
    3. update:指令所在模板被重新解析时调用
  • 备注:
    1. 指令定义时不加v-,但使用时要加v-
    2. 指令如果时多个单词,要使用kebab-case命名方式,不要使用camelCase命名

十四、生命周期

在这里插入图片描述

1、含义

  • 又名:生命周期回调函数、生命周期函数、生命周期钩子
  • 是什么:Vue在关键时刻帮我们调用的一些特殊名称函数
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
  • 生命周期函数的this指向是vm 或组件实例对象

2、挂载流程

  • beforeCreate初始化,生命周期、事件,但数据代理还未开始

    此时,无法通过vm访问到data中的数据、methods中的方法

  • created初始化,数据监测、数据代理

    此时,可以通过vm访问到data中的数据、methods中的方法

  • beforeMount此阶段Vue开始解析模板,生成虚拟DOM(内存中),页面还不能显示解析好的内容

    此时,页面呈现的是未经Vue编译的DOM结构;所有对DOM的操作,最终都不奏效

  • mounted将内存中的虚拟DOM转为真实DOM,并插入页面

    此时,页面呈现的是经过Vue编译的DOM结构;对DOM的操作均有效(尽可能避免)

    至此,初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作

其中:

(1) Has “el” option?

​ NO: when vm.$mount(el) is called

​ YES:

(2) Has “template” option?

​ NO: Compile el’s outerHTML as template

​ YES: Compile template into render function

3、更新流程

  • beforeUpdatewhen data changes

    此时,数据最新的,但页面是旧的,即页面尚未和数据保持同步

  • updated根据新数据,生成新的虚拟DOM,随后与旧的虚拟DOM进行比较,最终完成页面更新,即完成Model -> View的更新

    此时,数据最新的,页面也是最新的,即页面和数据保持同步

4、销毁流程

  • beforeDeatroywhen em.$destroy() is called

    此时,vm中所有:data、methods、指令等等,都处于可用状态,马上要执行销毁过程

    一般在此过程,关闭定时器、取消订阅消息、解绑自定义事件等收尾操作

  • destroyed

5、总结

vm的一生:

  • 将要创建 ===> 调用beforeCreate函数
  • 创建完毕 ===> 调用created函数
  • 将要挂载 ===> 调用beforeMount函数
  • 挂载完毕 ===> 调用mounted函数
  • 将要更新 ===> 调用beforeUpdate函数
  • 更新完毕 ===> 调用updated函数
  • 将要销毁 ===> 调用beforeDestroy函数
  • 销毁完毕 ===> 调用destroyed函数

常用的生命周期钩子

  • mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  • beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等收尾工作

关于销毁Vue实例

  • 销毁后借助Vue开发者工具看不到任何消息
  • 销毁后自定义事件会失效,但原生DOM事件依然有效
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值