头部背景图片
小畅的学习笔记 |
小畅的学习笔记 |

Vue.js学习笔记Day3-4.29

Vue.js学习笔记Day3-4.29

今日主要学习内容:

  • 使用Vue-resource实现品牌的增删查功能;
  • Vue中的动画;
    1. 使用过渡类名实现动画
    2. 使用第三方 CSS 动画库
    3. 使用动画钩子函数
    4. v-for 的列表过渡
  • 使用定义Vue组件;
    1. 什么是组件
    2. 组件化和模块化的不同
    3. 全局组件定义的三种方式
    4. 组件中展示数据和响应事件
    5. 使用components属性定义局部子组件
    6. 两种切换组件方法

开始和我一起Vue框架的学习吧~

一、使用Vue-resource实现品牌的增删查功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./lib/vue-2.4.0.js"></script>
    <script src="./lib/vue-resource-1.3.4.js"></script>
    <link rel="stylesheet" href="./lib/bootstrap-3.3.7.css">
</head>
<body>
    <div id="app">
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h3 class="panel-title">添加品牌</h3>
            </div>
            <div class="panel-body form-inline">
            <!-- <label>
                Id:
                <input type="text" v-model="id">
                </label> -->
            <label>
                Name:
                <input type="text" v-model="name" class="form-control">
            </label>

            <input type="button" value="添加" @click="add" class="btn btn-primary">

            </div>
        </div>

        <table class="table table-bordered table-hover table-striped">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Ctime</th>
                    <th>Operation</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="item in list" :key="item.id">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.ctime}}</td>
                    <td>
                        <a href="" @click.prevent="del(item.id)">删除</a>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    <script>
        // 全局配置数据接口的根域名
        //注意每次单独发起http请求的时候,请求的URL路径应该以相对路径开头,前面不能带‘/’,否则不会启用根路径拼接
        Vue.http.options.root = 'http://localhost:63342/vue/';
        //全局启用emulateJson选项,防止未添加的时候的情况
        Vue.http.options.emulateJSON = true;

        var vm = new Vue({
            el: '#app', //el指定vm要控制的元素
            data: { //data指定vm中要展示的数据
                name: '',
                list: [ //存放所有品牌列表的数组
                    {id: 1, name: '奔驰', ctime: new Date() },
                    {id: 2, name: '宝马', ctime: new Date() }
                ]
            },
            created(){ //当vm实例的data和methods初始化完毕后,vm实例会自动执行created这个生命周期函数
                this.getAllList();
            },
            methods:{ //methods指示我们要触发的方法
                getAllList(){ //获取所有的品牌列表
                // 分析:
                // 1. 由于已经导入了vue-resource这个包,所以可以直接通过this.$http来发起数据请求
                // 2. 根据接口API文档,知道获取列表的时候,应该发起一个get请求
                // 3. this.$http.get('url').then(function(result){})
                // 4. 当通过then指定回调函数之后,在回调函数中,可以拿到数据服务器返回的result
                // 5. 先判断result.status是否等于0,如果等于0,可以吧result.message赋值给this.list;如果不等于0,可以弹框提醒,获取数据失败!
                    this.$http.get('http://vue.studyit.io/api/getprodlist').then(result => {
                    //注意: 通过$http获取到的数据,都在 result.body中放着
                        var result = result.body;
                        if(result.status === 0){ //成功了
                            this.list = result.message;
                        }else{ //失败了
                            alert('获取数据失败!');
                        }
                    })
                },
                add(){ // 添加品牌列表到后台服务器
                // 分析:
                // 1. 通过查看数据API接口,发现要发送一个post请求this.$http.post
                // 2. this.$http.post()中接受三个参数:
                // 2.1 第一个参数:要请求的URL地址
                // 2.2 第二个参数:要提交给服务器的数据,要以对象形式提交给服务器(name:this.name)
                // 2.3 第三个参数:是一个配置对象,要以哪种表单数据类型提交过去(emulate JSON:true),以普通表单形式,将数据提交给服务器application/x-www-form-urlencoded
                // 3. 在post方法中,使用.then来设置成功的回调函数,如果想要拿到成功的结果,需要result.body
                    this.$http.post('http://vue.studyit.io/api/addproduct',{name: this.name},{emulateJSON:true}).then(result => {
                    //注意: 通过$http获取到的数据,都在 result.body中放着
                    //var result = result.body;
                        if(result.body.status === 0){ //成功了,添加完成后,只需要手动调用getAllList()就能刷新品牌列表
                            this.getAllList();
                            this.name = '';
                        }else{ //失败了
                            alert('添加失败!');
                        }
                    })
                },

                del(id){ //删除品牌列表
                    this.$http.get('http://vue.studyit.io/api/delproduct/' + id).then(result=>{
                        if(result.body.status === 0){ //成功了
                            this.getAllList();
                        }else{ //失败了
                            alert('删除失败!');
                        }
                    })
                },
            }
        });
    </script>
</body>
</html>

二、Vue中的动画

为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果,包括以下工具:

  • 在 CSS 过渡和动画中自动应用 class
  • 可以配合使用第三方 CSS 动画库,如 Animate.css
  • 在过渡钩子函数中使用 JavaScript 直接操作 DOM
  • 可以配合使用第三方 JavaScript 动画库,如 Velocity.js

Image1.png
Image2.png

1.使用过渡类名实现动画
  • 1.1设置HTML结构:
<div id="app">
    <input type="button" value="toggle" @click="flag=!flag">
    <!-- 需求: 点击按钮,让H3显示,再点击,让H3隐藏 -->
    <!-- 1.使用transition把需要被动画控制的元素包裹起来,transition是Vue官方提供-->
    <transition>
        <h3 v-if="flag">这是一个H3</h3>
    </transition>
</div>
  • 1.2创建VM 实例:
<script>
    var vm = new Vue({
        el: '#app', //el指定vm要控制的元素
        data: { //data指定vm中要展示的数据
            flag: false,
        },
        methods:{ //methods指示我们要触发的方法
        }
    })
</script>
  • 1.3定义两组类样式:
<!-- 2.自定义两组样式,来控制transition内部的元素实现动画 -->
<style>
    /*v-enter是一个时间点,进入之前,元素的起始状态,此时还没有开始进入*/
    /*v-leave-to是一个时间点,是动画离开之后,离开的终止状态,此时元素动画已经结束*/
    .v-enter,.v-leave-to{
        opacity: 0;
        transform: translateX(150px);
    }
    /*v-enter-active是入场动画时间段,v-leave-active是离场动画时间段*/
    .v-enter-active,.v-leave-active{
        transition: all 0.8s ease;
    }
</style>

注意:当设置时,可以自定义动画前缀,动画类改为.my-enter.my-leave-to

2.使用第三方 CSS 动画库
  • 2.1导入动画类库:
<link rel="stylesheet" href="./lib/animate.css">
<!-- 注意:入场使用bounceIn 离场使用bounceOut -->
  • 2.2定义 transition 及属性:
<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
    <h3 v-if="flag">这是一个H3</h3>
</transition>
  • 2.3使用:druation=”毫秒值”来统一设置入场时长和离场时长
<!-- 使用:druation="毫秒值"来统一设置入场时长和离场时长-->
<!-- 使用:druation="{enter:200,leave:400}"来分别设置入场时长和离场时长-->
<transition enter-active-class="bounceIn" leave-active-class="bounceOut" :druation="{enter:200,leave:400}">
    <h3 v-if="flag" class="animated">这是一个H3</h3>
</transition>
3.使用动画钩子函数
  • 3.1定义 transition 组件以及三个钩子函数:
<div id="app">
    <input type="button" value="加入购物车" @click="flag=!flag">
    <!-- 使用transition把小球包裹起来 -->
    <transition
    @before-enter="beforeEnter"
    @enter="enter"
    @after-enter="afterEnter">
    <div class="ball" v-show="flag"></div>
    </transition>
</div>
  • 3.2定义三个 methods 钩子方法:
methods:{ //methods指示我们要触发的方法
    // 注意:动画钩子函数的第一个参数:el,表示要执行动画的那个DOM元素,是个原生的JS DOM对象
    //大家可以认为,el是通过 document.getElementById('') 方式获取到的原生的JS DOM对象
    beforeEnter(el){
        //beforeEnter表示动画入场之前,此时动画尚未开始,可以在beforeEnter中设置元素开始动画之前的起始样式
        //设置小球开始动画之前的起始位置
        el.style.transform = "translate(0,0)";
    },
    enter(el,done){
        //这句话没有实际效用,但写了el.offsetWidth可以出现动画效果,可以认为它强制动画刷新
        el.offsetWidth;
        //enter 表示动画开始之后的样式,这里可以设置小球完成动画之后的结束状态
        el.style.transform = "translate(150px, 450px)";
        el.style.transition = 'all 1s ease'
        //这里的done()就是afterEnter函数,也就是:done是afterEnter函数的引用,不使用done会产生延迟
        done();
    },
    afterEnter(el){
        //动画完成之后会调用afterEnter
        //console.log('ok!');
        this.flag=!this.flag;
    },
}
  • 3.3定义动画过渡时长和样式:
<style>
    .ball{
        width: 15px;
        height: 15px;
        border-radius: 50%;
        background-color: red;
    }
</style>
4.v-for 的列表过渡
  • 4.1定义过渡样式:
<style>
    li{
        border: 1px dashed #999;
        margin: 5px;
        line-height: 35px;
        padding-left: 5px;
        font-size: 12px;
        width: 100%;
    }

    /* 用来实现鼠标滑动时显示粉色 */
    li:hover{
        background-color: hotpink;
        transition: all 0.4s ease;
    }

    /* 用来实现新加列表向上弹出显示 */
    .v-enter,
    .v-leave-to{
        opacity: 0;
        transform: translateY(80px);
    }

    .v-enter-active,
    .v-leave-active{
        transition: all 0.6s ease;
    }

    /* .v-move和.v-leave-active配合使用,能够实现列表后续的元素渐渐地漂上来的效果,更加平缓柔和 */
    .v-move{
        transition: all 0.6s ease;
    }
    .v-leave-active{
        position: absolute;
    }
</style>

组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用。

  • 4.2定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
<div id="app">
    <div>
        <label>
            Id:
            <input type="text" v-model="id">
        </label>
        <label>
            Name:
            <input type="text" v-model="name">
        </label>
        <input type="button" value="添加" @click="add">
    </div>

    <ul>
    <!-- 在实现列表过度的时候,如果需要过度的元素,是通过v-for循环渲染出来的,不能使用transition包裹,需要使用transitionGroup -->
    <!-- 如果要为v-for循环创建的元素设置动画,必须为每一个元素设置:key属性 -->
    <!-- appear用于实现刚进入页面时列表滑动显示效果 -->
    <!-- 通过为transition-group元素设置tag属性,指定它渲染为指定的元素,若不指定tag属性,则渲染为span标签,不符合语法规范 -->
        <transition-group appear tag="ul">
            <li v-for="(item,i) in list" :key="item.id" @click="del(i)">
            {{item.id}}---{{item.name}}
            </li>
        </transition-group>
    </ul>
</div>
  • 4.3定义 VM中的结构:
<script>
    var vm = new Vue({
        el: '#app', //el指定vm要控制的元素
        data: { //data指定vm中要展示的数据
            id: '',
            name: '',
            list: [
                {id:1,name: '张三'},
                {id:2,name: '李四'},
                {id:3,name: '王五'},
                {id:4,name: '赵六'},
            ]
        },
        methods:{ //methods指示我们要触发的方法
            add(){
                this.list.push({ id: this.id, name: this.name});
                this.id=this.name='';
            },
            del(i){
                this.list.splice(i,1);
            },
        }
    })
</script>
相关文章
  1. vue.js 1.x 文档
  2. vue.js 2.x 文档
  3. String.prototype.padStart(maxLength, fillString)
  4. js 里面的键盘事件对应的键码
  5. pagekit/vue-resource
  6. navicat如何导入sql文件和导出sql文件
  7. 贝塞尔在线生成器

三、使用定义Vue组件

1. 什么是组件:

组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;

2. 组件化和模块化的不同:
  • 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
  • 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
3. 全局组件定义的三种方式
1)使用 Vue.extend 配合 Vue.component 方法:

注意:如果使用Vue.component定义全局组件的时候,组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改写为小写的字母,同时,两个单词之前用-连接;如果不使用驼峰命名,则直接拿该名称来使用即可

// 1.1使用vue.extend来创建全局的Vue组件
var com1 = Vue.extend({
    //通过template属性,指定了组件要展示的HTML结构
    template:'<h3>这是使用Vue.extend创建的组件</h3>'
})

// 1.2使用Vue.component('组件的名称',创建出来的组件模板对象)
Vue.component('myCom1',com1)

Vue.component:

  • 第一个参数:组件的名称,将来在引用组件的时候,就是一个标签形式来引入它
  • 第二个参数:通过Vue.extend创建的组件,其中template就是组件将来要展示的HTML内容
Vue.component('myCom1',Vue.extend({
    template:'<h3>这是使用Vue.extend创建的组件</h3>'
}))
2)直接使用 Vue.component 方法:
  • 注意:无论是哪种方式创建出来的组件,组件的template属性指向的模板内容,必须有且只能有唯一的一个根元素
  • 用这种方法更简单,但是html语句书写起来没有提示更不方便书写
Vue.component('mycom2', {
    template: '<div><h3>这是直接使用Vue.component创建出来的组件</h3><span>123</span></div>'
});
3)将模板字符串,定义到script标签种:
  • 这是通过template元素在外部定义的组件结构,这个方式有代码的智能提示和高亮
  • 注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!
<!-- 在被控制的#app外面,使用template元素,定义组件的HTML模板结构 -->
<template id="temp1">
    <div>
        <h3>这是通过template元素在外部定义的组件结构</h3><span>123</span>
    </div>
</template>

同时,需要使用 Vue.component 来定义组件:

Vue.component('mycom3', {
    template: '#tmp1'
});
4. 组件中展示数据和响应事件
1)在组件中,data需要被定义为一个方法,例如:
  • 组件可以有自己的data数据
  • 组件的data和实例的data有点不一样,实例中的data可以作为一个对象,但是组件中的data必须是一个方法
  • 组件中的data出了必须作为一个方法之外,这个方法内部,还必须返回一个对象才行
  • 组件中的data数据和实例中的使用方式一模一样
Vue.component('mycom2', {
    template: '<h3>这是全局组件 ---{{msg}}</h3>',
    data:function(){
        return{
            msg: '这是组件中data定义的数据'
        };
    },
    methods:{
    }
});
2)在子组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的data属性中的值,需要使用this来访问;

【重点】:为什么组件中的data属性必须定义为一个方法并返回一个对象:因为共用同一个dataObj导致几个计时器会相互干扰

// 这是一个计数器的组件,身上有个按钮,每当点击按钮,让data中的count值+1
Vue.component('counter', {
    template: '#tmp1',
    data:function(){
        // return dataObj;
        return{
            count:0,
        };
    },
    methods:{
        increment(){
            this.count +=1
        }
    }
});
5.使用components属性定义局部子组件
1)组件实例定义方式:
var vm2 = new Vue({
    el:'#app2',
    data: {},
    methods: {},
    filters: {},
    directives: {},
    components: { //用于定义实例内部私有组件的
        login: {
            template: '<h1>这是私有的login组件</h1>'
        }
    },
    beforeCreate(){},
    created(){},
    beforeMount(){},
    mounted(){},
    beforeUpdate(){},
    updated(){},
    beforeDestroy(){},
    destroyed(){},
})
2)引用组件:
<div id="app2">
<login></login>
</div>
6.切换组件方法
方法一:使用flag标识符结合v-if和v-else切换组件(仅用于两个组件间切换)
  1. 页面结构:
<div id="app">
    <a href="" @click.prevent="flag=true">登录</a>
    <a href="" @click.prevent="flag=false">注册</a>
    <login v-if="flag"></login>
    <register v-else="flag"></register>
</div>
  1. Vue实例定义:
<script>
    Vue.component('login', {
        template: '<h3>登录组件</h3>'
    });
    Vue.component('register', {
        template: '<h3>注册组件</h3>'
    });
    var vm = new Vue({
        el: '#app', //el指定vm要控制的元素
        data: { //data指定vm中要展示的数据
            flag: false,
        },
        methods:{ //methods指示我们要触发的方法
        }
    })
</script>

缺陷:只能两个组件相互切换,更多组件无法使用v-if和v-else

方法二:使用:is属性来切换不同的子组件,并添加切换动画(可用于多个组件间切换)
  1. 组件实例定义方式:
<script>
    // 组件名称是一个字符串,所以放到:is里要用引号引起来
    Vue.component('login', {
        template: '<h3>登录组件</h3>'
    });
    Vue.component('register', {
        template: '<h3>注册组件</h3>'
    });
    var vm = new Vue({
        el: '#app', //el指定vm要控制的元素
        data: { //data指定vm中要展示的数据
            comName: '' //当前component中的:is绑定的组件名称
        },
        methods:{ //methods指示我们要触发的方法
        }
    })
</script>
  1. 使用component标签,来引用组件,并通过:is属性来指定要加载的组件:
<div id="app">
    <a href="" @click.prevent="comName='login'">登录</a>
    <a href="" @click.prevent="comName='register'">注册</a>
    <!-- Vue提供了component,来展示对应名称的组件 -->
    <!-- component是一个占位符,:is属性可以用来指定要展示的组件名称 -->
    <!-- 通过mode属性,设置组件切换时候的模式 -->
    <transition mode="out-in">
        <component :is="comName"></component>
    </transition>
    <!-- 总结:当前学习了几个Vue提供的标签 -->
    <!-- component,template,transition,transitionGroup -->
</div>

注意: 通过mode属性,设置mode=”out-in”,设置组件切换时候先出后进的模式 –>

  1. 添加切换样式:
<style>
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(150px);
}

.v-enter-active,
.v-leave-active{
transition: all 0.5s ease;
}
</style>
Lililich's Blog