【Vue】一

Vue简介

el和data的两种写法

        const v = new Vue({
            el: '#root',
            data: {
                name: '123'
            }
        })

动态指定el容器

        console.log(v)
        setTimeout(()=>{
            v.$mount('#root')
        },1000)

函数式返回data

            data: function() {
                return {
                    name: '123'
                }
            }

而不能写成箭头函数,因为箭头函数没有this,下面输出为window而不是vue

            data:()=> {
                console.log(this)
                return {
                    name: '123'
                }
            }

在对象中写明方法也可以简写为

            data() {
                console.log(this)
                return {
                    name: '123'
                }
            }

MVVM模型

M:模型(Model):Data中的数据

V:视图(View):模板代码

VM:视图模型(ViewModel):Vue实例

数据代理

Object.defineProperty方法(对象,新增属性,value)

let number = 18
        let person = {
            name: 'hikaru',
            sex: 'w',
            // age: 30
        }

        Object.defineProperty(person, "age", {
            value: number,
            enumerable: true, //设置新增属性可以枚举,默认为false
            writable: true, //设置新增属性可以被修改,默认为false
            configurable: true //设置新增属性可以被删除,默认为false
        })
        // 两种遍历方法
        for (let key in person) {
            console.log(person[key])
        }
        console.log(Object.keys(person))
        console.log(person)

get和set方法

        Object.defineProperty(person, "age", {
            // value: number,
            enumerable: true, //设置新增属性可以枚举,默认为false
            // writable: true, //设置新增属性可以被修改,默认为false
            // configurable: true, //设置新增属性可以被删除,默认为false
            get() {
                return number
            },
            set(value) {
                console.log(value)
            }

        })

get在当age被读取时,get函数(getter)就会被调用,且返回值就是age的值

set在当age被修改时,set函数(setter)就会被调用,且参数就是被修改的age值

get set方法与writable、configurable属性重复不能一起写

数据代理实现

通过一个对象实现对另一个对象的读写操作

Vue.config.productionTip = false
        let obj1 = {x:100}
        let obj2 = {y:200}

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

Vue中的数据代理:通过vm对象来代理data中的数据

vm(vue实体)将model中的data赋值给vm中的_data

数据代理: 将_data中所有的属性通过Object.defineProperty添加到vm中。

vm的data调用getter、setter方法时就会获取修改model中的data。

事件处理 v-on:xxx / @xxx

    <div id="root">
        <button v-on:click="getInfo1">Info1</button><br/>
        <button @click="getInfo2($event, 66)">Info2</button><br/>
        <a href="https://www.baidu.com" @click="changeTarget">baidu</a><br/>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: "#root",
            methods: {
                getInfo1() {
                    alert('info1')
                },
                getInfo2(event, number) {
                    console.log(number)
                },
                changeTarget(event) {
                    alert(event.target.href)
                    event.target.href += '/s?wd=vue'
                }
            },
        })
    </script>

只有data中的数据会被数据劫持代理,如果把method加入data也会被数据代理

Vue常用事件修饰符

1 prevent 阻止默认事件

js写法

        new Vue({
            el: "#root",
            methods: {
                getInfo1() {
                    alert('info1')
                },
                getInfo2(event, number) {
                    console.log(number)
                },
                changeTarget(e) {
                    alert(e.target.href)
                    e.preventDefault();

                }
            },
        })

Vue写法:@click.prevent

<a href="https://www.baidu.com" @click.prevent="changeTarget">baidu</a><br/>
2 stop 阻止事件向上级冒泡
3 once 事件只触发一次
4 capture 使用事件的捕获模式
5 self 只有event.target是当前操作的元素时才触发事件
    <div id="root" @click.prevent.self="getInfo">
        <button @click.prevent="getInfo">getInfo</button>
    </div>

冒泡到root的div时target仍是按钮

<button>getInfo</button>
6 passive 事件的默认行为立即执行,无需等待事件回调执行完毕

键盘事件

@keyup 在按键抬起的时候触发事件

@keydown 在按键按下的时候触发事件

常用按键别名

回车 Enter

删除 Delete

退出 Esc

空格 Spacce

换行 tab 需要配合keydown使用

上 up

下 down

左 left

右 right

    <div id="root">
        <input type="text" placeholder="输入字符回车后提示" @keyup.enter="getInfo">
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: "#root",
            methods: {
                getInfo(e) {
                    console.log(e.key + ', ' + e.keyCode)
                }
            }
        })
    </script>

e.key + ', ' + e.keyCode 获取键盘输入字符和字符编码

如回车 Enter 13

计算属性

1 使用插值语法实现

<div id="root">
        姓:<input type="text" v-model="firstName" ><br/>
        名:<input type="text" v-model="lastName"><br/>
        姓名:{{firstName + lastName}}
    </div>
</body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: "#root",
            data: {
                firstName: '张',
                lastName: '三'
            }
        })
    </script>

2 使用methods实现

<div id="root">
        姓:<input type="text" v-model="firstName" ><br/>
        名:<input type="text" v-model="lastName"><br/>
        姓名:{{getFullName()}}
    </div>
</body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: "#root",
            data: {
                firstName: '张',
                lastName: '三'
            },
            methods: {
                getFullName() {
                    return this.firstName.slice(0,3) + '-' + this.lastName;
                }
            }
        })
    </script>

使用有返回值的方法时必须加括号

3 计算属性 利用已经有的属性计算生成新属性

            computed: {
                fullName: {
                    get() {
                        return this.firstName.slice(0,3) + '-' + this.lastName;
                    },
                    set() {

                    }
                }
            }

底层使用的是Object.defineProperty,方法get在被计算的属性被修改、计算的属性读取时被调用

只有get方法的计算属性的简写形式
            computed: {
                fullName: function(){
                    return this.firstName.slice(0,3) + '-' + this.lastName;
                }
            }

监视属性

两种监视方法

①通过Vue实例化时的watch属性

            watch: {
                firstName: {
                    immediate: true,
                    handler(newValue, oldValue) {
                        console.log(newValue + '=>' + oldValue)
                    }
                }
            }

immediate表示在被监视属性初始化时就调用handler

handler方法在被监视属性被修改时就会被调用

②通过vm

vm.$watch('lastName', {
            immediate: true,
            handler(newValue, oldValue) {
                console.log(newValue + oldValue)
            }
        })

''为正常写法,不加引号是简写

在只有handler时的简写形式

            watch: {
                firstName(newValue, oldValue) {
                    console.log(newValue + oldValue)
                }
            }
        })
        vm.$watch('lastName', function(newValue, oldValue){
            console.log(newValue + oldValue)
        })

深度监视

            watch: {
                firstName: {
                    immediate: true,
                    deep: true,
                    handler(newValue, oldValue) {
                        console.log(newValue + '=>' + oldValue)
                    }
                }
            }

深度监视在数据有多层结构时会监视所有的层结构数据,默认为false

与计算属性的比较 需求:延迟显示

                watch: {
                firstName(val) {
                    setTimeout(()=>{
                        this.fullName = val + this.lastName
                    },1000
                    )    
                },
                lastName(val) {
                    setTimeout(()=>{
                        this.fullName = this.firstName + val
                    },1000
                    )    
                }

computer可以完成的功能,watch都能完成,反之则不然,如监视属性方便进行异步,而计算属性只能瞬时return

这里使用了箭头函数,但是函数中的this仍为vm,这是因为箭头函数没有自己的this,需要递归向上寻找this,而lastName为普通函数且其this为vm,故箭头函数中的this为vm

箭头函数与普通函数的使用原则

被Vue管理的函数使用普通函数,这样this指向的是vm实例 或者 组件对象

所有不被Vue管理的函数,使用箭头函数,这样this指向的是vm实例 或者 组件对象

如:定时器的回调函数、ajax的回调函数、Promise的回调函数等

class与stye的绑定 :class

    <body>
        <div id="root">
            <div class="basic" :class="classes" @click="changeMood">

            </div>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: '#root',
            data: {
                classes: 'normal'
            },
            methods: {
                changeMood() {
                    let choose = Math.floor(Math.random(2) * 3)
                    let moods = ['normal', 'happy', 'sad']
                    this.classes = moods[choose]
                }
            }
        })
    </script>

①字符串写法

②数组写法

        new Vue({
            el: '#root',
            data: {
                classArr: 'normal'
            },
            methods: {
                changeMood() {
                    let choose = Math.floor(Math.random(2) * 3)
                    let moods = ['normal', 'happy', 'sad']
                    this.classArr = moods[choose]
                }
            }
        })

③对象写法

            data: {
                classArr: 'normal',
                classObj: {
                    happy: false,
                    sad: true
                }
            },

条件渲染 v-if v-show

v-show=""中的表达式为真时,会为元素添加 style="display: none"

v-if 会直接让元素消失

列表渲染 v-for

遍历数组

        <div id="root">
            <h2>人员列表</h2>
            <ul v-for="(emp, index) in employeeList" :key="index">
                <li>{{emp.name}}-{{emp.age}}</li>
            </ul>
        </div>
        new Vue({
            el: '#root',
            data: {
                employeeList:[
                    {id: '001', name: '张三', age: 18},
                    {id: '002', name: '李四', age: 28},
                    {id: '003', name: '王五', age: 19}
                ]
            },
            methods: {

            }
        })

遍历对象

        <div id="root">
            <h2>人员列表</h2>
            <ul v-for="(val, key) in employeeList[0]">
                <li>{{val}} - {{key}}</li>
            </ul>
        </div>

接收对象的两个值先是value然后再是key

key的工作原理 虚拟DOM对比算法

key设置的属性为遍历对象的唯一标识

代码:

    <body>
        <div id="root">
            <h2>人员列表</h2>
            <ul v-for="(emp, index) in employeeList" :key="index">
                <li>{{index}} : {{emp.name}}-{{emp.age}} <input type="text"></li>
            </ul>
            <button @click="add">add</button>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: '#root',
            data: {
                employeeList:[
                    {id: '001', name: '张三', age: 18},
                    {id: '002', name: '李四', age: 28},
                    {id: '003', name: '王五', age: 19}
                ]
            },
            methods: {
                add() {
                    const e = {id: '004', name: '老六', age: 30}
                    this.employeeList.unshift(e)
                }
            }
        })
    </script>

出现的问题:

原因:

虚拟DOM对比算法,即是在数据发生变化的时候,生成的虚拟DOM会和原来的虚拟DOM依据key值进行比较,如果相同则直接复用原来的DOM结构,否则会生成新的DOM结构

如上图中,key为0的两个DOM比较,发现文本不同但是输入框相同(虚拟DOM不会考虑文本框内的内容),因此会生成新文本“老刘-30”,然后复用原来的输入框。

解决方法

①使用数据中的id作为key值

            <ul v-for="(emp, index) in employeeList" :key="emp.id">
                <li>{{index}} : {{emp.name}}-{{emp.age}} <input type="text"></li>
            </ul>

②或者使用不改变原有index顺序的插入方法

            methods: {
                add() {
                    const e = {id: '004', name: '老六', age: 30}
                    this.employeeList.push(e)
                }
            }

列表过滤

用watch实现

<body>
        <div id="root">
            <h2>人员列表</h2>
            <input v-model="keyWord" placeholder="请输入信息"/>
            <ul v-for="(person, index) in filPersons" :key="index">
                <li>{{person.name}}-{{person.age}}</li>
            </ul>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: '#root',
            data: {
                persons:[
                    {id: '001', name: '马冬梅', age: 18},
                    {id: '002', name: '周冬雨', age: 28},
                    {id: '003', name: '周杰伦', age: 19},
                    {id: '004', name: '温兆伦', age: 17}
                ],
                filPersons: [],
                keyWord: ''
            },
            methods: {

            },
            watch: {
                keyWord: {
                    immediate: true,
                    handler(val) {
                        this.filPersons = this.persons.filter((p)=>{
                            return p.name.indexOf(val) !== -1;
                        })
                    }
                }
            }
        })
    </script>

使用计算属性

    <body>
        <div id="root">
            <h2>人员列表</h2>
            <input v-model="keyWord" placeholder="请输入信息"/>
            <ul v-for="(person, index) in filPersons" :key="index">
                <li>{{person.name}}-{{person.age}}</li>
            </ul>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
            el: '#root',
            data: {
                persons:[
                    {id: '001', name: '马冬梅', age: 18},
                    {id: '002', name: '周冬雨', age: 28},
                    {id: '003', name: '周杰伦', age: 19},
                    {id: '004', name: '温兆伦', age: 17}
                ],
                keyWord: ''
            },
            methods: {

            },
            computed: {
                filPersons() {
                    return this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyWord) !== -1;
                    })
                }
            }
        })
    </script>

列表排序

            computed: {
                filPersons() {
                    const arr =  this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyWord) !== -1;
                    })
                    if(this.sortType) {
                        arr.sort((p1, p2) => {
                            return this.sortType === 1 ? p1.age-p2.age : p2.age-p1.age
                        })
                    }
                    return arr
                }
            }

收集表单数据为JSON数据: JSON.stringify

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script type="text/javascript" src="./js/vue.js"> </script>
        <style>
            button {
                margin-left: 2%;
            }
        </style>
    </head>
    <body>
        <div id="root">
            <form @submit.prevent="submit()">
                <label for="userName">账号:</label>
                <input type="text" id="userName" v-model="userInfo.userName"/><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/>

                性别: 
                男<input type="radio" name="sex" value="male" v-model="userInfo.sex"/>
                女<input type="radio" name="sex" value="female" v-model="userInfo.sex"/><br/><br/>

                爱好:
                学习<input type="checkbox" value="learning" v-model="userInfo.hobby">
                打游戏<input type="checkbox" value="game" v-model="userInfo.hobby"> 
                吃饭<input type="checkbox" value="eating" v-model="userInfo.hobby">
                <br/><br/>

                所属校区
                <select v-model="userInfo.school">
                    <option value="北京">北京</option>
                    <option value="上海">上海</option>
                    <option value="广州">广州</option>
                    <option value="深圳">深圳</option>
                </select>
                <br/><br/>

                其他信息
                <textarea v-model="userInfo.otherText">

                </textarea><br/><br/>

                <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="#">《用户协议》</a>
                <br/><br/>
                <button type="submit">提交</button>
            </form>

        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false
        const vm = new Vue({
            el: '#root',
            data: {
                userInfo: {
                    userName: '',
                    passWord: '',
                    age: '',
                    sex: 'male',
                    hobby: [],
                    school: '',
                    otherText: '',
                    agree: true
                }
            },
            methods: {
                submit() {
                    console.log(JSON.stringify(this.userInfo))
                }
            },
            computed: {

            }
        })
    </script>
</html>
posted @ 2022-05-24 20:35  Tod4  阅读(50)  评论(0)    收藏  举报