二十五、初识Vue.js

Vue.js是什么

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue第一个实例

<!--
        1. 引入Vue.js
        2. 创建Vue对象
            el:指定根element(选择器)
            data: 初始化数据(页面可以访问)
        3. 双向数据绑定:v-model
        4. 显示数据:{{xxx}}}
        5. 理解vue的mvvm实现
    -->
    <div id="app">
        <input type="text" v-model="username">
        <p>Hello {{username}}</p>
    </div>

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

    <script type="text/javascript">
        const vm = new Vue({ //配置对象(属性名必须是指定的一些名称)
            el:'#app',  //element:选择器,表明将页面哪个元素交给Vue管理
            data:{  //数据(model)
                username:'Vue'
            }
        })
        vm.username = 'Kobe';
    </script>

模板语法

  1. 模板的理解:
    动态的html页面包含了一些JS语法代码
    大括号表达式指令(以v-开头的自定义标签属性)
  2. 双大括号表达式
    语法: {{exp}}
    功能: 向页面输出数据
    可以调用对象的方法
  3. 指令一: 强制数据绑定
    功能: 指定变化的属性值
    完整写法:
    v-bind:xxx='yyy' //yyy会作为表达式解析执行
    简洁写法:
    :xxx='yyy'
  4. 指令二: 绑定事件监听
    功能: 绑定指定事件名的回调函数
    完整写法:
    v-on:click='xxx'
    简洁写法:
    @click='xxx'
<div id="app">
   <h2>1. 双大括号表达式</h2>
   <p>{{msg}}</p><!-- textContent -->
   <p>{{msg.toUpperCase()}}</p>
   <p v-text="msg"></p><!-- textContent -->
   <p v-html="msg"></p><!-- innerHTML -->

   <h2>2. 指令一: 强制数据绑定</h2>
   <!-- <img src="imgUrl" alt="大V"> -->
   <!-- <img v-bind:src="imgUrl" alt="大V"> -->
   <img :src="imgUrl" alt="大V">

   <h2>3. 指令二: 绑定事件监听</h2>
   <button v-on:click="test">test1</button>
   <!-- <button @click="test2('abc')">test2</button> -->
   <button @click="test2(msg)">test2</button>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
   new Vue({
       el: '#app',
       data: {
           // msg: 'I Will Back!'
           msg: '<a href="http://www.baidu.com">百度网</a>',
           imgUrl: 'https://cn.vuejs.org/images/logo.png'
       },
       methods: {
           test(){
               alert('hihi~~');
           },
           test2(content){
               alert(content);
           }
       }
   })
</script>

Vue计算属性和监视

  1. 计算属性
    在computed属性对象中定义计算属性的方法
    在页面中使用{{方法名}}来显示计算的结果
  2. 监视属性:
    通过通过vm对象的$watch()或watch配置来监视指定的属性
    当属性变化时, 回调函数自动调用, 在函数内部进行计算
  3. 计算属性高级:
    通过getter/setter实现对属性数据的显示和监视
    计算属性存在缓存, 多次读取只执行一次getter计算
    getter:属性的get方法
    setter:属性的set方法
<div id="demo">
    姓: <input type="text" placeholder="First Name" v-model="firstName"><br>
    名: <input type="text" placeholder="Last Name" v-model="lastName"><br>
    <!--fullName1是根据fistName和lastName计算产生-->
    姓名1(单向): <input type="text" placeholder="Full Name1" v-model="fullName1"><br>
    姓名2(单向): <input type="text" placeholder="Full Name2" v-model="fullName2"><br>
    姓名3(双向): <input type="text" placeholder="Full Name3" v-model="fullName3"><br>

    <p>{{fullName1}}</p>
    <p>{{fullName1}}</p>
    <p>{{fullName1}}</p>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    const vm = new Vue({
        el: '#demo',
        data: {
            firstName: 'A',
            lastName: 'B',
            // fullName1: 'A B'
            fullName2: 'A B'
        },
        computed: {
            // 什么时候执行:初始化显示/相关的data属性数据发生改变
            // 计算并返回当前属性的值
            fullName1(){//计算属性的一个方法,方法的返回值作为属性值
                console.log('fullName1()');
                return this.firstName + ' ' + this.lastName;
            },
            fullName3: {
                /*
                回调函数要满足3个条件:
                    1、你定义的;
                    2、你没有调用;
                    3、但最终它执行了
                什么时候调用?
                用来做什么?
                */
                // 回调函数,当需要读取当前属性值时回调,根据相关的数据计算并返回当前属性的值
                get(){
                    return this.firstName + ' ' + this.lastName;
                },
                // 回调函数,监视当前属性值的变化,当属性值发生改变时回调,更新相关的属性数据
                set(value){// value就是fullName3的最新属性值
                    const names = value.split(' ');
                    this.firstName = names[0];
                    this.lastName = names[1];
                }
            }
        },
        watch: {//配置监视
            firstName: function(value){//firstName发生了变化
                console.log(this);//就是VM对象
                this.fullName2 = value + ' ' + this.lastName;
            }
        }
    })
    vm.$watch('lastName', function(value){
        // 更新fullName2
        this.fullName2 = this.firstName + ' ' + value;
    });
</script>

class与style绑定

  1. 理解
    在应用界面中, 某个(些)元素的样式是变化的
    class/style绑定就是专门用来实现动态样式效果的技术
  2. class绑定: :class='xxx'
    xxx是字符串
    xxx是对象
    xxx是数组
  3. style绑定
    :style="{ color: activeColor, fontSize: fontSize + 'px' }"
    其中activeColor/fontSize是data属性
<style type="text/css">
        .aClass{
            color: red;
        }
        .bClass{
            color: blue;
        }
        .cClass{
            font-size: 30px;
        }
</style>

<div id="demo">
    <h2>1. class绑定: :class='xxx'</h2>
    <p class="cClass" :class="a">xxx是字符串</p>
    <p :class="{aClass: isA, bClass: isB}">xxx是对象</p>
    <p :class="['aClass', 'cClass']">xxx是数组</p>

    <h2>2. style绑定</h2>
    <p :style="{color: activeColor, fontSize: fontSize + 'px'}">style绑定</p>

    <button @click="update">更新</button>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#demo',
        data: {
            a: 'aClass',
            isA: true,
            isB: false,
            activeColor: 'red',
            fontSize: 20
        },
        methods: {
            update(){
                this.a = 'bClass';
                this.isA = false;
                this.isB = true;
                this.activeColor = 'green';
                this.fontSize = 30;
            }
        }
    })
</script>

条件渲染

  1. 条件渲染指令
    v-if
    v-else
    v-show
  2. 比较v-if与v-show
    如果需要频繁切换 v-show 较好
<div id="demo">
    <p v-if="ok">成功了</p>
    <p v-else="true">失败了</p>

    <p v-show="ok">表白成功</p>
    <p v-show="!ok">表白失败</p>

    <button @click="ok=!ok">切换</button>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#demo',
        data: {
            ok: false
        }
    })
</script>

列表渲染

  1. 列表显示
    数组: v-for / index
    对象: v-for / key
  2. 列表的更新显示
    删除item
    替换item
div id="demo">
    <h2>测试: v-for 遍历数组</h2>
    <ul>
        <li v-for="(p, index) in persons" :key="index">
            {{index}}---{{p.name}}---{{p.age}}
            ---<button @click="deleteP(index)">删除</button>
            ---<button @click="updateP(index, {name: 'Lucy', age: 20})">更新</button>
        </li>
    </ul>

    <h2>测试: v-for 遍历对象</h2>
    <ul>
        <li v-for="(value, key) in persons[1]" :key="key">
            {{value}}---{{key}}
        </li>
    </ul>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    /*
    vue本身只是监视了persons的改变,没有监视数组内部数据的改变
    vue重写了数组中的一系列改变数组内部数据的方法(先调用原生,再更新界面)-->数组内部改变,界面自动变化
    */
    new Vue({
        el: '#demo',
        data: {
            persons: [
                {name: 'Tom', age:18},
                {name: 'Jack', age:16},
                {name: 'Bob', age:19},
                {name: 'Rose', age:17}
            ]
        },
        methods: {
            deleteP(index){
                // 删除persons中指定index的p
                this.persons.splice(index, 1);
            },
            updateP(index, newP){
                // 并没有改变persons本身,数组内部发生变化,但并没调用变异方法,Vue不会更新界面
                // this.persons[index] = newP;
                // this.persons = [];
                this.persons.splice(index, 1, newP);
            }
        }
    })
</script>

列表过滤与排序

div id="demo">
    <input type="text" v-model="searchName">
    <ul>
        <li v-for="(p, index) in filterPersons" :key="index">
            {{index}}---{{p.name}}---{{p.age}}
        </li>
    </ul>
    <div>
        <button @click="setOrderType(1)">年龄升序</button>
        <button @click="setOrderType(2)">年龄降序</button>
        <button @click="setOrderType(0)">原本顺序</button>
    </div>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#demo',
        data: {
            searchName: '',
            orderType: 0,// 0代表原本、1代表升序、2代表降序
            persons: [
                {name: 'Tom', age:18},
                {name: 'Jack', age:16},
                {name: 'Bob', age:19},
                {name: 'Rose', age:17}
            ]
        },
        computed: {
            filterPersons(){
                // 取出相关的数据
                const {searchName, persons, orderType} = this;
                // 最终需要显示的数组
                let fPersons;
                // 对persons进行过滤
                fPersons = persons.filter(p => p.name.indexOf(searchName)!==-1);
                // 排序
                if(orderType!==0){
                    fPersons.sort(function(p1, p2){
                        // 1代表升序、2代表降序
                        if(orderType===2){
                            // 如果返回负数则p1在前,返回正数则p2在前
                            return p2.age - p1.age;
                        }else{
                            return p1.age - p2.age;
                        }
                    })
                }
                return fPersons;
            }
        },
        methods: {
            setOrderType(orderType){
                this.orderType = orderType;
            }
        }
    })
</script>

事件处理

  1. 绑定监听:
    v-on:xxx="fun"
    @xxx="fun"
    @xxx="fun(参数)"
    默认事件形参: event
    隐含属性对象: $event
  2. 事件修饰符:
    .prevent : 阻止事件的默认行为 event.preventDefault()
    .stop : 停止事件冒泡 event.stopPropagation()
  3. 按键修饰符
    .keycode : 操作的是某个keycode值的健
    .enter : 操作的是enter键
<div id="example">

    <h2>1. 绑定监听</h2>
    <button @click="test1">test1</button>
    <button @click="test2('hello')">test2</button>
    <!-- <button @click="test3($event)">test3</button> -->
    <button @click="test3">test3</button>
    <button @click="test4(123, $event)">test4</button>

    <h2>2. 事件修饰符</h2>
    <div style="width: 200px;height: 200px;background: red" @click="test5">
        <div style="width: 100px;height: 100px;background: blue" @click.stop="test6"></div>
    </div>

    <a href="http://www.baidu.com" @click.prevent="test7">去百度</a>

    <h2>3. 按键修饰符</h2>
    <input type="text" @keyup.13="test8">
    <input type="text" @keyup.enter="test8">

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#example',
        data: {
            test1(){
                alert('test1');
            },
            test2(msg){
                alert(msg);
            },
            test3(event){
                alert(event.target.innerHTML);
            },
            test4(number, event){
                alert(number + '---' + event.target.innerHTML);
            },
            test5(){
                alert('out');
            },
            test6(){
                alert('inner');
            },
            test7(){
                alert('点击了');
            },
            test8(event){
                // if(event.keyCode === 13){
                alert(event.target.value + ',' + event.keyCode);
                // }
            }
        }
    })
</script>

表单输入绑定

  1. 使用v-model(双向数据绑定)自动收集数据
    text/textarea
    checkbox
    radio
    select
<div id="demo">
    <form action="/xxx" @submit.prevent="handleSubmit">
        <span>用户名: </span>
        <input type="text" v-model="username"><br>

        <span>密码: </span>
        <input type="password" v-model="pwd"><br>

        <span>性别: </span>
        <input type="radio" id="female" value="女" v-model="gender">
        <label for="female">女</label>
        <input type="radio" id="male" value="男" v-model="gender">
        <label for="male">男</label><br>

        <span>爱好: </span>
        <input type="checkbox" id="basket" value="basket" v-model="hobby">
        <label for="basket">篮球</label>
        <input type="checkbox" id="foot" value="foot" v-model="hobby">
        <label for="foot">足球</label>
        <input type="checkbox" id="pingpang" value="pingpang" v-model="hobby">
        <label for="pingpang">乒乓</label><br>

        <span>城市: </span>
        <select v-model="cityId">
            <option value="">未选择</option>
            <option :value="city.id" v-for="(city, index) in allCitys" :key="index">{{city.name}}</option>
        </select><br>
        <span>介绍: </span>
        <textarea rows="10" v-model="desc"></textarea><br><br>

        <input type="submit" value="注册">
    </form>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#demo',
        data: {
            username: '',
            pwd: '',
            gender: '女',
            hobby: ['foot'],
            allCitys: [{id: 1, name: 'BJ'}, {id: 2, name: 'SH'}, {id: 3, name: 'GD'}],
            cityId: '1',
            desc: ''
        },
        methods:{
            handleSubmit(){
                console.log(this.username, this.pwd);
            }
        }
    })
</script>

Vue实例_生命周期

  1. vue对象的生命周期
    1). 初始化显示
    • beforeCreate()
    • created()
    • beforeMount()
    • mounted()
      2). 更新显示:this.xxx = value
    • beforeUpdate()
    • updated()
      3). 销毁vue实例: vm.$destory()
    • beforeDestory()
    • destoryed()
  2. 常用的生命周期方法
    mounted(): 发送ajax请求, 启动定时器等异步任务
    beforeDestory(): 做收尾工作, 如: 清除定时器
<div id="test">
    <button @click="destroyVM">destroy vm</button>
    <p v-show="isShow">Vue实例的生命周期</p>
    <p>{{isShow}}</p>
    <p>{{isShow}}</p>
    <p>{{isShow}}</p>
    <p>{{isShow}}</p>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#test',
        data: {
            isShow: true
        },
        // 1、初始化阶段
        beforeCreate(){
            console.log('beforeCreate()');
        },
        created(){
            console.log('created()');
        },
        beforeMount(){
            console.log('beforeMount()');
        },
        mounted(){// 初始化显示之后立即调用(1次)
            console.log('mounted()');
            this.intervalId = setInterval(() => {
                console.log('-------->');
                this.isShow = !this.isShow;// 更新数据
            }, 1000);
        },
        // 2、更新阶段
        beforeUpdate(){
            console.log('beforeUpdate()');
        },
        updated(){
            console.log('updated()');
        },
        // 3、死亡阶段
        beforeDestroy(){// 死亡之前调用(1次)
            console.log('beforeDestroy()');
            // 清除定时器
            clearInterval(this.intervalId);
        },
        destroyed(){
            console.log('destroyed()');
        },
        methods: {
            destroyVM(){
                // 干掉VM
                this.$destroy();
            }
        }
    })
</script>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容