Loading

& VUE 学习记录-1

VUE学习记录

Day01

什么是Vue.js

  • Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机App, Vue语法也是可以用于进行手机App开发的,需要借助于Weex)
  • Vue.js 是前端的主流框架之一,和Angular.js、React.js 一起,并成为前端三大主流框架!
  • Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)
  • 前端的主要工作?主要负责MVC中的V这一层;主要工作就是和界面打交道,来制作前端页面效果;

为什么要学习流行框架

  • 企业为了提高开发效率:在企业中,时间就是效率,效率就是金钱;
    • Jquery + art-template + Ajax
    • 在没有前端框架之前,我们前端需要经常的操作DOM元素;
    • 在项目中,vue 能够简化DOM操作,让程序员根本不用操作任何DOM元素,就能渲染页面;
    • 企业中,使用框架,能够提高开发的效率;
  • 提高开发效率的发展历程:原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js / Vue.js(能够帮助我们减少不必要的DOM操作;提高渲染效率;双向数据绑定的概念【通过框架提供的指令,我们前端程序员只需要关心数据的业务逻辑,不再关心DOM是如何渲染的了】)
  • 在Vue中,一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑;

框架的区别

  • 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目。
    node 中的 express;
  • 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
    • 从Jquery 切换到 Zepto
    • 从 EJS 切换到 art-template

Node(后端)中的MVC 与 前端中的 MVVM 之间的区别

  • MVC 是后端的分层开发概念;
  • MVVM是前端视图层的概念,主要关注于 视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View , VM ViewModel

Vue之 - 基本的代码结构和插值表达式v-cloak

  • 使用 插值表达式,存在内容闪烁的问题,但是,v-text没有闪烁问题;
  • 在插值表达式中,可以使用 v-cloak 解决闪烁问题;
  • 插值表达式只会插入内容,并不会清楚其余的内容; v-text 会把元素中之前的内容都清空!

Vue指令之v-text和v-html

<div id="app">
   <div v-text="msg3"></div>
   <div v-html="msg3"></div>
</div>


<script>
    //这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
    let vue = new Vue({
        //指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
        el:'#app',   

        //data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
        data:{
            msg3:'<h6>小标题</h6>',
        }
    });

</script>

image-20210617122720209

Vue指令之v-bind的三种用法

  • 直接使用指令v-bind
  • 使用简化指令:
  • 在绑定的时候,拼接绑定内容::title=”btnTitle + ‘, 这是追加的内容’”
<body>
    <!--创建一个容器,将来使用VUE就可以控制这个指定容器中的所有DOM元素-->
    <div id="app">
        <!--v-bind: 可以为元素的属性绑定一些数据-->
        <input type="button" value="按钮" v-bind:title="btnTitle">
        <hr>
        <input type="button" value="按钮" v-bind:id="customIdName" >
        <hr>

        <!--v-bind: 这个指令可以被简写成 :-->
        <input type="button" value="按钮" :title="btnTitle">
        <hr>
        <input type="button" value="按钮" :id="customIdName" >
        <hr>

        <!--v-bind: 指令中,如果想要实现表达式的拼接,被拼接的字符串一定要用引号包裹起来,否则会被当做变量解析-->
        <input type="button" value="按钮" :title="btnTitle + '这是追加的内容'">
    </div>

    <script>
        //这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
        let vue = new Vue({
            el:'#app',//指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
            data:{//data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
                btnTitle:'这是按钮的自定义title值',
                customIdName:'这是按钮的自定义id值'
            }
        });

    </script>
</body>

Vue指令之v-on跑马灯效果

跑马灯效果

   <!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.5.9.js"></script>

    </head>

    <body>
    <div id="app">
        <!--<input type="button" value="浪起来" id="btn1" v-on:click="lang" >-->
        <input type="button" value="浪起来" id="btn1" @click="lang" >
        <input type="button" value="stop浪" id="btn2" @click="stop">
        <hr>
        <h3>{{ msg }}</h3>

    </div>

    <script>
        let vue = new Vue({
            el:'#app',
            data:{
                msg: '猥琐发育别浪~',
                intervalId: null //定时器的id
            },
            methods:{
                lang(){
                    if(this.intervalId != null){
                        return;
                    }
                    //定时器
                    this.intervalId = setInterval(() => {
                        let header = this.msg.substring(0,1)
                        let body = this.msg.substring(1)
                        this.msg = body + header
                    },300);
                },
                stop(){
                    clearInterval(this.intervalId)
                }
            }
        });

    </script>
    </body>
    </html>

Vue指令之v-on的缩写@事件修饰符

事件修饰符:

事件修饰符之.stop详解

<!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.5.9.js"></script>

    <style>
        #inner {
            background-color: pink;
            height: 150px;
            width: 200px;
        }

        #inner2 {
            background-color: pink;
            height: 150px;
            width: 200px;
        }
    </style>

</head>

<body>
<div id="app">
    <!--此处点击按钮 会触发冒泡事件 btnClick->innerClick -->
    <div id="inner" @click="innerClick">
        <input type="button" value="按钮" @click="btnClick">
    </div>
    <hr>

    <div id="inner2" @click="innerClick">
        <!--.stop阻止冒泡事件-->
        <input type="button" value="按钮" @click.stop="btnClick">
    </div>
</div>

<script>
    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {
            innerClick() {//内部的div点击事件
                console.log("内部的div点击事件")
            },
            btnClick(){//按钮的点击事件
                console.log("按钮的点击事件")

            }
        }
    });
</script>
</body>
</html>

image-20210617123146048

事件修饰符之.capture .self .once 详解

    <body>
    <div id="app">
        <!--a链接-->
        <a href="http://www.baidu.com" @click.prevent="linkClick">百度百度</a>

        <!--表单-->
        <form @submit.prevent="postForm">
            <input type="text" name="username">
            <input type="text" name="gender">
            <input type="submit" value="提交表单">
        </form>
    </div>

    <script>
        let vue = new Vue({
            el: '#app',
            data: {},
            methods: {
                linkClick(){
                    console.log("按钮呗点击了")
                },
                postForm(){
                    console.log("触发了表单的submit")
                    //阻止了form的默认行为之后,就可以在这里就可以自定义调用接口
                }
            }
        });

    </script>
    </body>

事件修饰符之.prevent详解

<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.5.9.js"></script>

    <style>
        .inner {
            background-color: pink;
            height: 150px;
            width: 200px;
        }

    </style>

</head>

<body>
<div id="app">
    <!--.capture添加事件侦听器时使用事件捕获模式-->
    <div class="inner" @click.capture="innerClick">
        <input type="button" value="按钮" @click="btnClick">
    </div>
    <hr>

    <div class="inner" @click.self="innerClick">
        <!--.self只当事件在该元素本身(比如不是子元素)触发时触发回调-->
        <input type="button" value="按钮" @click="btnClick">
    </div>
        <hr>
    <!--.once只执行一次-->
    <div class="inner" @click.once="innerClick">
        <input type="button" value="按钮" @click="btnClick">
    </div>
</div>

<script>
    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {
            innerClick() {//内部的div点击事件
                console.log("内部的div点击事件")
            },
            btnClick(){//按钮的点击事件
                console.log("按钮的点击事件")

            }
        }
    });
</script>
</body>

capture

image-20210617123244400

self

image-20210617123300194

once

image-20210617123309616

Vue指令之v-model双向数据绑定

  • v-bind: 指令只能实现数据的单项绑定,从data自动同步到view上
  • 在Vue中,只有v-model指令实现了数据的双向绑定,其他指令都是单向
  • 注意:v-model只能应用在表单元素中
  • 表单元素 例:input text radio checkbox textarea select

简易计算器案例

<body>
        <div id="app">
            <input type="text" v-model="n1">
            <select v-model="opt">
                <option value="+">+</option>
                <option value="-">-</option>
                <option value="*">*</option>
                <option value="/">/</option>
            </select>
            <input type="text" v-model="n2">
            <input type="button" value="=" @click="calc">
            <input type="text" v-model="result">

        </div>

        <script>
            let vue = new Vue({
                el: '#app',
                data: {
                    n1: 0,
                    opt: '+',
                    n2: 0,
                    result: 0,
                },
                methods: {
                    calc(){
                        /*switch (this.opt){
                            case "+":
                                this.result = parseFloat(this.n1) + parseFloat(this.n2);
                                break;
                            case "-":
                                this.result = parseFloat(this.n1) - parseFloat(this.n2);
                                break;
                            case "*":
                                this.result = parseFloat(this.n1) * parseFloat(this.n2);
                                break;
                            case "/":
                                this.result = parseFloat(this.n1) / parseFloat(this.n2);
                                break;
                        }*/
                        eval(`this.result = parseFloat(this.n1) ${this.opt} parseFloat(this.n2);`)



                    }
                }
            });

        </script>
    </body>

在Vue中使用样式

使用class样式

  • 数组
    <h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
  • 数组中使用三元表达式
    <h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
  • 数组中嵌套对象
    <h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
  • 直接使用对象
    <h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>

使用内联样式

  • 1.直接在元素上通过:style的形式,书写样式对象
    • <h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
  • 2.将样式对象,定义到 data中,并直接引用到:style
    • 在data上定义样式:
    • ```html
      data: {

      h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }

    }
    ```

    • 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
      <h1 :style="h1StyleObj">这是一个善良的H1</h1>
    1. 在 :style 中通过数组,引用多个 data 上的样式对象
      • 在data上定义样式:
        ```
        data: {
        h1StyleObj: { color: ‘red’, ‘font-size’: ‘40px’, ‘font-weight’: ‘200’ },
        h1StyleObj2: { fontStyle: ‘italic’ }
        }
      • 在元素中,通过属性绑定的形式,将样式对象应用到元素中: <h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>

Vue指令之v-for和key属性

  • 1.迭代数组
<ul>
  <li v-for="(item, i) in list">索引:{{i}} --- 姓名:{{item.name}} --- 年龄:{{item.age}}</li>
</ul>
  • 2.迭代对象中的属性

循环遍历对象身上的属性

<div v-for="(val, key, i) in userInfo">{{val}} --- {{key}} --- {{i}}</div>
  • 3.迭代数字
<p v-for="i in 10">这是第 {{i}} 个P标签</p>
     <ul>
            <!--今后,只要涉及到了v-for这种循环,推荐给循环的每一项添加:key属性-->
            <!--:key属性,只接受number或string类型的数据,不要直接为:key指定对象-->
            <!--:key 指定的值必须具有唯一性-->
            <li v-for="(item,i) in list" :key="item.id">
                <input type="checkbox">
                {{ item.id }}---{{ item.name }}---{{ i }}</li>
        </ul>

2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

Vue指令之v-if和v-show

  • v-if和v-show只有一个作用,就是根据指定的标识符,切换元素的显示和隐藏状态
  • v-if是实时的创建和移除元素,从而达到元素的显示和隐藏
  • v-show是通过为元素 添加活移除 display:none 来实现隐藏和显示的
  • 一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。

品牌管理案例

Vue调试工具vue-devtools

作业

    <style>
        .normal{
            color: blue;
        }
        .active{
            color: red;
            font-weight: bold;
        }

    </style>
    </head>
    <body>

    <div id="app">
        <ul>
            <li v-for="(item,i) in list" :key="item.id"
                :class="['normal',{active:i == selectedIndex?true:false}]"
            @click="change(i)">
                <input type="checkbox" :checked="i == selectedIndex">
                {{item.id}},{{item.name}},{{item.age}},{{item.sex}}
            </li>
        </ul>

    </div>
    <script>
        let vue = new Vue({
            el: '#app',
            data: {
                selectedIndex: 0,
                list: [
                    {id: 1, name: '王五', age: 12, sex: '男'},
                    {id: 2, name: '张三', age: 13, sex: '男'},
                    {id: 3, name: '小红', age: 14, sex: '女'},
                ]
            },
            methods: {
                change(i){
                    this.selectedIndex = i
                }
            }
        });
    </script>
    </body>

过滤器

  • 过滤器的使用注意事项:
  • 1.Vue.filter(‘过滤器的名称’,’过滤器的处理函数’)
  • 2.注意:过滤器的处理函数中,第一个形参,功能已经被规定好了,永远都是管道符前面的值
  • 3.调用过滤器 {{ item.ctime | formatDate }}
  • 4.在调用过滤器的时候 可以传递参数{{ item.ctime | formatDate(‘传递参数’) }}
  • 5.注意:调用过滤器传递的参数 只能从处理函数的第二个形参开始接收 因为第一个形参已经被管道符前面的值给占用了
  • 6.注意:过滤器的处理函数中 必须返回一个值
  • 7.可以连续使用管道符 调用多个过滤器 最终输出的结果 永远以最后一个过滤器为准
  • 8.注意:过滤器只能使用在差值表达中 或者 v-bind中 不能使用在其他地方 比如v-text就不支持

全局过滤器

<label>{{cTime | dataFormat()}}</lable>

       // 定义一个全局过滤器
        Vue.filter('dataFormat', function (input, pattern = '') {
            var dt = new Date(input);
            // 获取年月日
            var y = dt.getFullYear();
            var m = (dt.getMonth() + 1).toString().padStart(2, '0');
            var d = dt.getDate().toString().padStart(2, '0');

            // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
            // 否则,就返回  年-月-日 时:分:秒
            if (pattern.toLowerCase() === 'yyyy-mm-dd') {
                return `${y}-${m}-${d}`;
            } else {
                // 获取时分秒
                var hh = dt.getHours().toString().padStart(2, '0');
                var mm = dt.getMinutes().toString().padStart(2, '0');
                var ss = dt.getSeconds().toString().padStart(2, '0');

                return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
            }
        });

私有过滤器

当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器

<div id="app">
        <label>{{msg | msgFilter | addStr}}</label>
    </div>

    <script>

        Vue.filter('msgFilter',function (msg){
            // let s = msg.replace('纯洁','邪恶');
            //  /g是全部匹配
            let s = msg.replace(/纯洁/g,'邪恶');
            console.log(s)
            return s;
        });

        let vue = new Vue({
            el: '#app',
            data: {
                msg: '曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁'
            },
            methods: {
            },
            filters:{
                addStr:function (data) {
                    return data+'~~~~~~~~~~~~~~~';
                },
                //当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器
                msgFilter:function (data) {
                    return data+'=============';
                },
            }
        });
    </script>

自定义指令

官方文档:https://cn.vuejs.org/v2/guide/custom-directive.html

全局自定义指令

        <label>搜索:
            <input type="text" @change="search" v-model="keywords" v-focus>
        </label>

    Vue.directive('focus',{
          //全局自定义 获得焦点的v-focus指令
        //Vue 自定义指令的名称中,不需要写v-前缀,但是,在调用自定义指令的时候,必须在起那么加上v-前缀
        //参数列表中的第一个参数,永远是el 表示被绑定指令的那个元素
        //如果要操作元素的样式,写到bind就行
        bind:function (el){//当指令绑定到的元素,被Vue实例解析的时候,就会立即执行bind函数
            // console.log(el)
            //el.focus();//如果想要让文本框获得焦点,那么,文本框必须先插入到文档中才能生效
            // el.style.color='red'

        },
        //今后在自定义指令的时候,如果需要操作元素的JS行为 最好写到inserted中
        inserted:function (el){//调用时机:当指令绑定到的元素,被插入到文档的父节点的时候,调用inserted函数
            // console.log('2 inserted执行了')
            el.focus();
        }
    })

私有自定义指令

<th  v-color="'green'" v-bold="1000" v-italic>操作</th>


let vue = new Vue({
        el: '#app',
        data: {},
        methods: {},
        //私有过滤器
        filters:{},
        //私有指令
        directives:{
            //让指定元素字体加粗的指令
            bold:{
                bind(el,binding){
                    console.log(binding.value)
                    el.style.fontWeight = binding.value
                },
                inserted(el){}
            },
            //让文字倾斜的指令
            italic:function (el,binding) {
                //此处用到了指令函数的简写形式,如果指令给定的是function,
                // 则等同于把这个function中的代码,
                // 分别定义到了bind和update中去;
                el.style.fontStyle="italic"

            }
        },
    });

image-20210617123948684

键盘修饰符

    <label>NAME:
            <input type="text" v-model="name" @keyup.enter="add">
    </label>

vue实例的生命周期

image-20210617124005356

  • 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
  • 生命周期钩子:就是生命周期事件的别名而已;
  • 生命周期钩子 = 生命周期函数 = 生命周期事件
  • 主要的生命周期函数分类:
    • 创建期间的生命周期函数:
    • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
    • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
    • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
    • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
    • 运行期间的生命周期函数:
    • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
    • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
    • 销毁期间的生命周期函数:
    • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
    • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
<!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="../day01/lib/vue-2.5.9.js"></script>
</head>

<body>
<div id="app">
    <input type="button" value="ChangeMsg" @click="msg='数据被修改了'">
    <h3 id="myh3">{{ msg }}</h3>
</div>

<script>

    let vue = new Vue({
        el: '#app',
        data: {
            msg: 'message'
        },
        methods: {
            show(){
                console.log('show方法被调用了')
            }
        },
        //第一个生命周期函数 【创建阶段】
        beforeCreate(){
            // console.log(this.msg)
            // this.show()
        },
        //第二个生命周期函数 【创建阶段】
        //当执行到created函数的时候,data和methods都已经初始化完毕了,此时,可以随意的去访问 其中的数据或方法了
        //结论:如果要操作data中的数据,或调用methods中的函数,最早,只能在created函数中进行。
        created(){
            console.log(this.msg)
            this.show()
        },
        //第三个生命周期函数 表示即将挂载  【创建阶段】
        //当模板页面被编译好之后,就会立即执行beforeMount这个函数
        //此时,我们的HTML代码结构,已经在内存中创建好了,但是,尚未挂载到页面中
        //结论:在这个函数中,页面上的DOM元素是原始的插值表达式之类的VUE代码
        beforeMount() {
            // let elementById = document.getElementById('myh3');
            // console.log(elementById.innerHTML)
        },
        //第四个生命周期函数,表示页面已经完成了渲染,
        // 同时,mounted函数的执行,标志着创建阶段的结束,从此以后,Vue实例,就从创建阶段,进入到运行阶段
        //结论:如果大家要引用一些第三方的插件来操作DOM元素了,最好在mounted中去操作DOM元素,因为这时候才是真正的页面
        mounted(){
           /* let elementById = document.getElementById('myh3');
            console.log(elementById.innerHTML)*/
        },

        beforeUpdate(){
            /*let elementById = document.getElementById('myh3');
            console.log(elementById.innerHTML)*/
        },
        updated(){
            let elementById = document.getElementById('myh3');
            console.log(elementById.innerHTML)
        }
    });
    //Vue的实例,也分为三个阶段:分别是创建阶段、运行阶段、销毁阶段
    //在实例运行的三个阶段中,总是伴随着各种各样的事件,那个,这些事件,统称为实例的生命周期函数(钩子函数、生命周期事件)
</script>
</body>
</html>

vue-resource 实现 get, post, jsonp请求

使用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.5.9.js"></script>
    <!--vue-resource 只能在vue的后面导入-->
    <script src="lib/vue-resource-1.3.4.js"></script>
</head>

<body>
<div id="app">
    <input type="button" value="Get请求" @click="getInfo">
    <input type="button" value="Post请求" @click="postInfo">
    <input type="button" value="jsonp请求" @click="jsonpInfo">
</div>

<script>
    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {
            //get方式请求数据
            /*getInfo(){
                this.$http.get("http://www.liulongbin.top:3005/api/getlunbo").then(function (data) {
                    console.log(data)
                    console.log(data.body)
                })
            }*/
            async getInfo(){
                // let data = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                // console.log(data.body)
                // 此处{ body } 是取data中的body节点的内容!!!
                let { body } = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                console.log(body)
            },
            async postInfo(){
                let { body } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
                console.log(body)
            },
            async jsonpInfo(){
                let { body } = await this.$http.jsonp("http://www.liulongbin.top:3005/api/jsonp")
                console.log(body)
            }
        }
    });
</script>
</body>
</html>

axios结合vue发起请求

<!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.5.9.js"></script>
    <script src="lib/axios-v0.17.1.js"></script>
</head>

<body>
<div id="app">
    <input type="button" value="Get请求" @click="getInfo">
    <input type="button" value="Post请求" @click="postInfo">
    <!--axios 不支持发送jsonp请求-->
    <!--<input type="button" value="jsonp请求" @click="jsonpInfo">-->
</div>

<script>
    //把axios挂载到Vue构造函数的原型上
    Vue.prototype.$http = axios
    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {
            async getInfo(){
                // let result = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
                // console.log(result)

                // let {data} = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
                // console.log(data)

                let {data} = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
                console.log(data)
            },

            async postInfo(){
                let { data } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
                console.log(data)
            }
        }
    });
</script>
</body>
</html>

Vue中的动画

使用过渡类名

  1. html结构
    <div id="app">
    <input type="button" value="动起来" @click="myAnimate">
    <!-- 使用 transition 将需要过渡的元素包裹起来 -->
    <transition name="fade">
      <div v-show="isshow">动画哦</div>
    </transition>
    </div>
  2. VM实例
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
    el: '#app',
    data: {
    isshow: false
    },
    methods: {
    myAnimate() {
      this.isshow = !this.isshow;
    }
    }
    });
  3. 定义两组类样式
    /* 定义进入和离开时候的过渡状态 */
    .fade-enter-active,
    .fade-leave-active {
      transition: all 0.2s ease;
      position: absolute;
    }
    
    /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
    .fade-enter,
    .fade-leave-to {
      opacity: 0;
      transform: translateX(100px);
    }

使用第三方 CSS 动画库

https://cn.vuejs.org/v2/guide/transitions.html#自定义过渡类名

  1. 导入动画类库
    <link rel="stylesheet" type="text/css" href="./lib/animate.css">
  2. 定义transition及属性
    <transition
    enter-active-class="fadeInRight"
    leave-active-class="fadeOutRight"
    :duration="{ enter: 500, leave: 800 }">
      <div class="animated" v-show="isshow">动画哦</div>
    </transition>

使用动画钩子函数

  1. 定义 transition 组件以及三个钩子函数:
    <div id="app">
       <input type="button" value="加入购物车" @click="flag=!flag">
    
       <transition
        @before-enter="beforeEnter"
        @enter="enter"
        @after-enter="afterEnter">
           <div id="ball" v-show="flag"></div>
       </transition>
    </div>
  2. 定义三个 methods 钩子方法:
    let vue = new Vue({
           el: '#app',
           data: {
               flag: false //显示的状态
           },
           methods: {
               beforeEnter(el){//小球开始动画之前的起始状态
                   el.style.transform='translate(0,0)'
               },
               enter(el,done){//小球动画结束之后的结束状态
                   //这里是固定写法,如果不写el.offsetWidth就无法实现动画效果
                   el.offsetWidth
                   el.style.transform='translate(150px,300px)'
                   el.style.transition='all 1s ease'
                   //当动画执行完毕后,会自动调用done这个函数,这个done就是afterEnter函数的引用
                   done()
               },
               afterEnter(el){//小球动画结束之后的回调函数,用来做一些清理工作
                   this.flag = !this.flag
               },
           }
       });

v-for 的列表过渡

https://cn.vuejs.org/v2/guide/transitions.html#列表的进入和离开过渡

  1. 定义过渡样式:
    <style>
    .list-enter,
    .list-leave-to {
      opacity: 0;
      transform: translateY(10px);
    }
    
    .list-enter-active,
    .list-leave-active {
      transition: all 0.3s ease;
    }
    </style>
  2. 定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
    <div id="app">
    <input type="text" v-model="txt" @keyup.enter="add">
    
    <transition-group tag="ul" name="list">
      <li v-for="(item, i) in list" :key="i">{{item}}</li>
    </transition-group>
    </div>
  3. 定义 VM中的结构:
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        txt: '',
        list: [1, 2, 3, 4]
      },
      methods: {
        add() {
          this.list.push(this.txt);
          this.txt = '';
        }
      }
    });

视频中代码:

<!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>
    <link rel="stylesheet" href="./lib/animate.css">
    <script src="lib/vue-2.5.9.js"></script>
    <script src="lib/axios-v0.17.1.js"></script>

    <style>
        ul{
            list-style: none;
            padding: 0;
            margin: 0;
        }

        li{
            line-height: 30px;
            border: 1px dashed #ccc;
            margin: 5px;
            font-size: 12px;
            padding-left: 10px;
            width: 500px;
            cursor: pointer;
        }
        li:hover{
            background-color: orange;
            box-shadow: 0 0 7px gray;
            /*transition: all 0.6s ease;*/
        }

        .v-enter,
        .v-leave-to{
            opacity: 0;
            transform: translateY(200px);
        }

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

        .v-move{/*让元素被改变定位的时候,有一个缓动效果*/
            transition: all 0.5s ease;
        }

        .v-leave-active{/*表示要被删除的哪个元素,让即将被移除的元素,脱离标准流,这样,后面的元素就能渐渐的浮动上来*/
            position: absolute;
        }
    </style>
</head>


<body>
<div id="app">

    <div>
        Id: <input type="text" v-model="id">
        Name: <input type="text" v-model="name">
        <input type="button" value="添加" @click="add">
    </div>

    <transition-group tag="ul">
        <li v-for="(item,i) in list" :key="item.id" @click="remove(i)">{{item.id}}-- {{item.name}}</li>
    </transition-group>
</div>

<script>
    let vue = new Vue({
        el: '#app',
        data: {
            list: [
                {id: 1,name: '高军军'},
                {id: 2,name: '付哥哥'},
                {id: 3,name: '玉姐姐'},
                {id: 4,name: '斌哥哥'}
            ],
            id: '',
            name: ''
        },
        methods: {
            remove(i){
                this.list.splice(i,1)
            },
            add(){
                const p = {id: this.id,name: this.name}
                // this.list.push(p)
                 this.list.unshift(p)//放最前面
                this.id = this.name = ''
            }
        }
    });
</script>
</body>
</html>

列表的排序过渡

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

  • v-movev-leave-active 结合使用,能够让列表的过渡更加平缓柔和:
    .v-move{
    transition: all 0.8s ease;
    }
    .v-leave-active{
    position: absolute;
    }

演示transition中name属性的重要性

<!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>
    <link rel="stylesheet" href="./lib/animate.css">
    <script src="lib/vue-2.5.9.js"></script>
    <script src="lib/axios-v0.17.1.js"></script>

    <style>
        .v-enter,
        .v-leave-to{
            opacity: 0;
            transform: translateX(100px);
        }

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

        .fade-enter,
        .fade-leave-to{
            opacity: 0;
            transform: translateX(100px);
        }

        .fade-enter-active,
        .fade-leave-active{
            transition: all 3s ease;
        }

    </style>
</head>

<body>
<div id="app">
    <input type="button" value="Toggle" @click="flag=!flag">
    <transition>
    <h3 v-show="flag">111111111</h3>
    </transition>

    <hr>

    <input type="button" value="Toggle" @click="flag2=!flag2">
    <transition name="fade">
        <h3 v-show="flag2">111111111</h3>
    </transition>

</div>

<script>
    let vue = new Vue({
        el: '#app',
        data: {
            flag: true,
            flag2: true
        }
    });
</script>
</body>
</html>

Day02

定义Vue组件

  • 什么是模块化:模块化是从代码的角度出发,分析项目,把项目中一些功能类似的代码,单独的抽离为一个个的模块;那么为了保证大家以相同的方式去封装模块,于是我们就创造了模块化的规范(CommonJS规范);
    • 模块化的好处:方便项目的开发;和后期的维护与扩展;今后如果需要某些固定功能的模块,则直接拿来引用就行,提高了项目开发效率!
  • 什么是组件化:从UI的角度出发考虑问题,把页面上有重用性的UI解构和样式,单独的抽离出来,封装为单独的组件;
    • 组件化的好处:随着项目规模的发展,我们手里的组件,会越来越多,这样,我们今后一个页面中的UI,几乎都可以从手中拿现成的组件拼接出来;方便项目的开发和维护;

全局组件定义的三种方式

第一种方式:

  1. 先调用 Vue.extend() 得到组件的构造函数:
    // 创建全局组件的第一种方式:   component
    const com1 = Vue.extend({
      template: '<h1>这是创建的第一个全局组件</h1>' // template 属性,表示这个组件的 UI 代码解构
    })
  2. 通过 Vue.component('组件的名称', 组件的构造函数) 来注册全局组件:
    // 使用 Vue.component 向全局注册一个组件
    // Vue.component('组件的名称', 组件的构造函数)
    Vue.component('mycom1', com1)
  3. 把注册好的全局组件名称,以标签形式引入到页面中即可:
    <!-- 如何引入一个全局的Vue组件呢? 直接把 组件的名称,以标签的形式,放到页面上就好了! -->
    <mycom1></mycom1>

第二种方式:

  1. 直接使用 Vue.component('组件名称', { 组件模板对象 })
    const com2Obj = {
      // 1. template 属性中,不能单独放一段文本,必须用标签包裹起来;
      // 2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹;
      template: '<div><h2>这是直接使用 Vue.component 创建出来的组件</h2><h3>红红火火</h3></div>'
    }
    
    // 定义全局的组件
    // Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象
    Vue.component('mycom2', com2Obj)

第三种方式:

  1. 先使用template标签定义一个模板的代码解构:
    <!-- 定义一个 template 标签元素  -->
    <!-- 使用 Vue 提供的 template 标签,可以定义组件的UI模板解构 -->
    <template id="tmpl">
    <div>
      <h3>哈哈,这是在外界定义的组件UI解构</h3>
      <h3>我是来捣乱的</h3>
    </div>
    </template>
  2. 使用Vue.component注册组件:
    // 这是定义的全局组件
    Vue.component('mycom3', {
      template: '#tmpl'
    })

注意: 从更抽象的角度来说,每个组件,就相当于是一个自定义的元素; 注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

定义私有组件

    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        components: {//定义实例中私有组件的 组件名称 和组件结构
            'mycom4': {
                template: '<h6>啦啦啦啦啦啦</h6>'
            }
        }
    })

组件中展示数据和响应事件

Vue.component('mycom', {
      template: '<h3 @click="show">这是自定义的全局组件:{{ msg }}</h3>',
      data: function () { // 在 组件中,可以有自己的私有数据,但是,组件的 data 必须是一个 function,并且内部 return 一个 数据对象
        return {
          msg: '哈哈哈'
        }
      },
      methods: { // 尝试定义组件的私有方法
        show() {
          console.log('触发了组件的私有show方法!')
        }
      }
    })

【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象

通过计数器案例演示

<!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>
    <!--1.导入Vue包-->
    <script src="../day01/lib/vue-2.5.9.js"></script>
</head>

<body>
<!--2.创建要控制的区域-->
<div id="app">
    <counter></counter>
    <counter></counter>
</div>

<script>
    const o = { count: 0 }
    //定义全局的组件
    //Vue.component的第二个参数,即接收组件的构造函数,同时也接收组件的一个对象
    Vue.component('counter', {
        template: `<div>
                    <input type="button" value="+1" @click="add">
                    <h3>当前count值为:{{count}}</h3>
                   </div>`,
        //为什么要把组件中的data定义为一个function呢?因为这样做的话,每当我们在页面上引用一次组件,
        // 必然会先调用这个data function,从而得到一个当前组件私有的数据对象;
        data: function (){
            //这是官方推荐的
            return {
                count: 0
            }

            //这是自己改造后的形式
            //如果使用此种方式,当我们在页面上多次引用组件时,o始终是同一个对象,就会造成数据联动!!!
            // return o;
        },
        methods: {
            add(){//点击按钮让组件的count值自增+1
                this.count++
            }
        }
    })
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {}
    })
</script>


</body>
</html>

使用flag标识符结合v-ifv-else切换组件

<!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>
    <!--1.导入Vue包-->
    <script src="../day01/lib/vue-2.5.9.js"></script>
</head>

<body>
<!--2.创建要控制的区域-->
<div id="app">
    <input type="button" value="显示登录" @click="flag=true">
    <input type="button" value="显示注册" @click="flag=false" >

    <login v-if="flag"></login>
    <reg v-else="flag"></reg>
</div>

<script>
    Vue.component('login',{
        template: `<h3>登录模块1</h3>`
    })

    Vue.component('reg',{
        template: `<h3>注册模块2</h3>`
    })
    const vm = new Vue({
        el: '#app',
        data: {
            flag: true
        },
        methods: {}
    })
</script>
</body>
</html>

使用component标签的:is属性来切换组件,并添加动画

<!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="../day01/lib/vue-2.5.9.js"></script>

    <style>
        .v-enter{
            /*即将进入时候的坐标*/
            opacity: 0;
            transform: translateX(100px);
        }

        .v-leave-to{
            /*离开时候,最终到达的位置*/
            opacity: 0;
            transform: translateX(-100px);
        }

        .v-enter-active,
        .v-leave-active{
            transition: all 0.4s ease;
            position: absolute;
        }
    </style>

</head>

<body>
<div id="app">
    <!--transition transition-group template component-->
    <!--通过component的:is属性 可以显示指定【名称】的组件-->
    <!--<component :is="componentId"></component>-->
    <a href="#" @click="comId='com1'">显示组件1</a> <br>
    <a href="#" @click="comId='com2'">显示组件2</a> <br>
    <a href="#" @click="comId='com3'">显示组件3</a> <br>
    <a href="#" @click="comId='com4'">显示组件4</a> <br>

    <!--mode="out-in"先离开之后再进入-->
    <transition mode="out-in">
     <component :is="comId"></component>
    </transition>
</div>

<script>
    Vue.component('com1',{
        template: `<h3>组件1-</h3>`
    })
    Vue.component('com2',{
        template: `<h3>组件2--</h3>`
    })
    Vue.component('com3',{
        template: `<h3>组件3---</h3>`
    })
    Vue.component('com4',{
        template: `<h3>组件4----</h3>`
    })
    const vm = new Vue({
        el: '#app',
        data: {
            comId: 'com1'
        },
        methods: {}
    })
</script>
</body>
</html>

父组件向子组件传值

父组件向子组件传递普通数据和对象

<div id="app">
    <!--父组件如果想给子组件传递数据,则需要使用属性绑定的形式-->
    <!--这样,子组件身上的自定义数据 就是你要传递给子组件的数据-->
    <com1 :obj="msgObj" :value="parentMsg"></com1>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            parentMsg: '普通值',
            msgObj: {//对象
                address: '北京',
                location: '顺义---马坡南'
            }
        },
        methods: {},
        components: {
            'com1': {
                template: `<h3>好好 {{obj}} ---- {{value}}</h3>`,
                props: ['obj','value']
            }
        }
    })
</script>

父组件向子组件传递方法

<div id="app">
    <!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
    <!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
    <com1 @showme="show"></com1>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            show(){
                console.log('有人调用了父组件中的show方法')
            }
        },
        components: {
            'com1': {
                <!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
                template: `<div>
                            <input type="button" value="这是子组件的按钮" @click="btnClick">
                           </div>`,
                methods: {
                    btnClick(){
                        //console.log('okok');
                        //调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
                        this.$emit('showme')
                    }
                }
            }
        }
    })
</script>

子组件向父组件传值

<div id="app">
    <!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
    <!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
    <com1 @showme="show"></com1>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            msgFormSon: ''
        },
        methods: {
            show(arg1){
                // console.log('有人调用了父组件中的show方法' + arg1)
                //把子组件传递过来的数据,保存到父组件的data中
                this.msgFormSon = arg1
                console.log(this.msgFormSon)
            }
        },
        components: {
            'com1': {
                <!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
                template: `<div>
                            <input type="button" value="这是子组件的按钮" @click="btnClick">
                           </div>`,
                data(){
                    return {
                        sonMsg: '这是子组件中的数据'
                    }

                },
                methods: {
                    btnClick(){
                        //console.log('okok');
                        //调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
                        //子组件向父组件传值本质上还是调用了父组件传递过来的方法,只不过,子组件在调用的时候把数据当做参数,传给这个方法了
                        this.$emit('showme',this.sonMsg)
                    }
                }
            }
        }
    })
</script>

评论列表案例

目标:主要练习父子组件之间传值

<body>
<div id="app">
    <cmt-box @add="addNewCnt"></cmt-box>

    <ul>
        <cmt-item v-for="(item,i) in list" :key="i" :item="item"></cmt-item>
    </ul>
</div>
<script>
    Vue.component('cmt-item',{
        template: `<ul>
                      <li>
                        <h3>评论人:{{ item.name }}</h3>
                        <h5>评论内容:{{ item.content }}</h5>
                      </li>
                   </ul>`,
        props:["item"]

    })

    Vue.component('cmt-box',{
        template: `
        <div>
            <label>评论人:</label>
            <br>
            <input type="text" v-model="name">
            <br>
            <label>评论内容:</label>
            <br>
            <textarea v-model="content"></textarea>
            <br>
            <input type="button" value="发表评论" @click="postComment">
        </div>`,
        data: function() {
            return {
                name: '',
                content: ''
            }
        },
        methods: {
            postComment(){//发表评论
                const cmt = {name: this.name,content: this.content}
                this.$emit('add',cmt)
            }
        },
    })

    const vm = new Vue({
        el: '#app',
        data: {
            list: [
                {name:'张三',content:'沙发1'},
                {name:'111',content:'沙发2'},
                {name:'qqq',content:'沙发3'},
                {name:'eee',content:'沙发4'}
            ]
        },
        methods: {
            addNewCnt(obj){//添加新评论
                 console.log('okokok')
                this.list.push(obj)
            }
        }
    })
</script>
</body>

使用this.$refs来获取元素

<div id="app">
    <input type="button" value="点击获取元素的内容" @click="getInfo" ref="btn">
    <h3 ref="myh3">{{msg}}</h3>
</div>
<script>

    const vm = new Vue({
        el: '#app',
        data: {
            msg: '000'
        },
        methods: {
            getInfo(){//点击按钮,获取H3中的文本内容
                console.log(this.$refs.myh3.innerHTML)
                console.log(this.$refs.btn.value)
            }
        }
    })
</script>

使用this.$refs来获取组件

<body>
<div id="app">
    <input type="button" value="获取页面上的组件" @click="getCom">
    <com1 ref="mycom"></com1>
</div>
<script>
    Vue.component('com1',{
        template: `
            <h3>这是一个小组件 {{msg}}</h3>
        `,
        data: function (){//子组件的私有数据
            return {
                msg: 'ok'
            }
        },
        methods: {//子组件的方法
            show(){
                console.log('有人调用了子组件的方法')
            }
        }
    })
    const vm = new Vue({
        el: '#app',
        data: {
            msg: '000'
        },
        methods: {
            getCom(){
                // console.log(this)
                //修改子组件上的数据
                // this.$refs.mycom.msg = '123'
                //调用子组件中的方法
                this.$refs.mycom.show()
            }
        }
    })
</script>
</body>

在Vue组件中data和props的区别

  1. data 在组件中,要被定义成function并返回一个对象
  2. props 在组件中,要被定义成数组,其中,数组的值都是字符串名,表示父组件传递过来的数据;
  3. props 的数据,不要直接拿来修改,如果想要修改,必须在 data 上重新定义一个 属性,然后把属性的值 从 this.props 拿过来;

data 上的数据,都是组件自己私有的, data 上的数据,都是可读可写的 props 数据,都是外界传递过来的数据, props 中的数据只能读取,不能重新写入

什么是路由

  1. 对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
  2. 对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
  3. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);
  4. 前端的路由:就是根据不同的Hash地址,在页面上展示不同的前端组件;

在 vue 中使用 vue-router

  1. 导入 vue-router 组件类库:
    <!-- 1. 导入 vue-router 组件类库 -->
    <script src="./lib/vue-router-2.7.0.js"></script>
  2. 使用 router-link 组件来导航
    <!-- 2. 使用 router-link 组件来导航 -->
    <router-link to="/login">登录</router-link>
    <router-link to="/register">注册</router-link>
  3. 使用 router-view 组件来显示匹配到的组件
    <!-- 3. 使用 router-view 组件来显示匹配到的组件 -->
    <router-view></router-view>
  4. 创建使用Vue.extend创建组件
    // 4.1 使用 Vue.extend 来创建登录组件
    var login = Vue.extend({
      template: '<h1>登录组件</h1>'
    });
    
    // 4.2 使用 Vue.extend 来创建注册组件
    var register = Vue.extend({
      template: '<h1>注册组件</h1>'
    });
  5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
    // 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
    var router = new VueRouter({
      routes: [
        { path: '/login', component: login },
        { path: '/register', component: register }
      ]
    });
  6. 使用 router 属性来使用路由规则
    // 6. 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      router: router // 使用 router 属性来使用路由规则
    });

设置路由高亮 linkActiceClass

<!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.5.9.js"></script>
    <!-- 1. 导入路由JS文件 -->
    <script src="./lib/vue-router-v3.0.1.js"></script>

    <style>
        .router-link-active {
            color: red;
            font-weight: bold;
            font-style: italic;
            font-size: 20px;
            text-decoration: underline;
        }
        .my-active {
            color: orange;
            font-size: 30px;
        }
    </style>
</head>

<body>
<div id="app">
    <!-- 路由链接 -->
    <router-link to="/login">登录</router-link>
    <router-link to="/reg">注册</router-link>

    <!-- 展示路由组件的容器 -->
    <router-view></router-view>
</div>

<script>
    //2.定义两个要切换的组件
    const login = {
        template: '<h3>登录组件</h3>'
    }
    const reg = {
        template: '<h3>登录组件</h3>'
    }
    //3. 创建路由对象
    const router = new VueRouter({
        routes: [//路由规则的数组
            // { path: '/', component: login },
            { path: '/', redirect: '/login' },     // node 的 express 框架中,有 res.redirect('/login')
            {path: '/login',component: login},
            {path: '/reg',component: reg},
        ],
        linkActiceClass: 'my-actice' //配置默认被选中路由的高亮类名,默认类名为 router-link-actice
    })
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router // 4. 把路由对象,挂载到 VM 实例上
    });
</script>
</body>

</html>

设置路由切换动效

<!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.5.9.js"></script>
    <!-- 1. 导入路由JS文件 -->
    <script src="./lib/vue-router-v3.0.1.js"></script>

    <style>
        .router-link-active {
            color: red;
            font-weight: bold;
            font-style: italic;
            font-size: 20px;
            text-decoration: underline;
        }
        .my-active {
            color: orange;
            font-size: 30px;
        }
        .v-enter,
        .v-leave-to {
            opacity: 0;
            transform: translateX(100px);
        }
        .v-enter-active,
        .v-leave-active {
            transition: all 0.3s ease;
            position: absolute;
        }
    </style>
</head>

<body>
<div id="app">
    <!-- 路由链接 -->
    <router-link to="/login">登录</router-link>
    <router-link to="/reg">注册</router-link>

    <!-- 展示路由组件的容器 -->
    <transition>
        <router-view></router-view>
    </transition>
</div>

<script>
    // 2. 定义两个要切换的组件
    const login = {
        template: '<h3>登录组件</h3>'
    }
    const reg = {
        template: '<h3>注册组件</h3>'
    }
    // 3. 创建路由对象
    const router = new VueRouter({
        routes: [ // 路由规则的数组
            // { path: '/', component: login },
            { path: '/', redirect: '/login' },     // node 的 express 框架中,有 res.redirect('/login')
            { path: '/login', component: login },
            { path: '/reg', component: reg }
        ],
        linkActiveClass: 'my-active' // 配置默认被 选中路由的高亮类名的 , 默认类名为 router-link-active
    })
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router // 4. 把路由对象,挂载到 VM 实例上
    });
</script>
</body>

</html>

路由传参

?拼接传参

<div id="app">
    <!-- 路由链接 -->
    <router-link to="/login?id=10">登录</router-link>
    <router-link to="/reg">注册</router-link>

    <!-- 展示路由组件的容器 -->
    <transition>
      <router-view></router-view>
    </transition>
  </div>

  <script>
    // 2. 定义两个要切换的组件
    const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
      template: '<h3>登录组件----{{$route.query.id}}</h3>',
      created() {
        console.log(this.$route.query)
        console.log(this.$route.query.id)
      }
    }
    const reg = {
      template: '<h3>注册组件</h3>'
    }

    // 3. 创建路由对象
    const router = new VueRouter({
      routes: [ // 路由规则的数组
        { path: '/', redirect: '/login' },
        { path: '/login', component: login },
        { path: '/reg', component: reg }
      ],
      linkActiveClass: 'my-active'
    })

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      router // 4. 把路由对象,挂载到 VM 实例上
    });
  </script>

在路由规则中定义参数

<body>
  <div id="app">
    <!-- 路由链接 -->
    <router-link to="/login/10/zs">登录</router-link>
    <router-link to="/reg">注册</router-link>

    <!-- 展示路由组件的容器 -->
    <transition>
      <router-view></router-view>
    </transition>
  </div>

  <script>
    // 2. 定义两个要切换的组件
    const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
      template: '<h3>登录组件----{{ $route.params.id }} --- {{ $route.params.name }}</h3>',
      created() {
        console.log(this.$route)
      }
    }
    const reg = {
      template: '<h3>注册组件</h3>'
    }

    // 3. 创建路由对象
    const router = new VueRouter({
      routes: [ // 路由规则的数组
        { path: '/', redirect: '/login' },
        { path: '/login/:id/:name', component: login },
        { path: '/reg', component: reg }
      ],
      linkActiveClass: 'my-active'
    })

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      router // 4. 把路由对象,挂载到 VM 实例上
    });
  </script>

路由中使用prop获取参数

{ path: '/login/:id/:name', component: login ,props: true},
const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
        props: ['name','id'],
        template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
        created() {
            console.log(this.$route)
        }
    }
<div id="app">
    <!-- 路由链接 -->
    <router-link to="/login/10/zs">登录</router-link>
    <router-link to="/reg">注册</router-link>

    <!-- 展示路由组件的容器 -->
    <transition>
        <router-view></router-view>
    </transition>
</div>

<script>
    // 2. 定义两个要切换的组件
    const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
        props: ['name','id'],
        template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
        created() {
            console.log(this.$route)
        }
    }
    const reg = {
        template: '<h3>注册组件</h3>'
    }
    // 3. 创建路由对象
    const router = new VueRouter({
        routes: [ // 路由规则的数组
            { path: '/', redirect: '/login' },
            { path: '/login/:id/:name', component: login ,props: true},
            { path: '/reg', component: reg }
        ],
        linkActiveClass: 'my-active'
    })

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router // 4. 把路由对象,挂载到 VM 实例上
    });
</script>

使用 children 属性实现路由嵌套

<div id="app">
    <router-link to="/account">Account</router-link>

    <router-view></router-view>
  </div>

  <script>
    // 父路由中的组件
    const account = Vue.extend({
      template: `<div>
        这是account组件
        <router-link to="/account/login">login</router-link> | 
        <router-link to="/account/register">register</router-link>
        <router-view></router-view>
      </div>`
    });

    // 子路由中的 login 组件
    const login = Vue.extend({
      template: '<div>登录组件</div>'
    });

    // 子路由中的 register 组件
    const register = Vue.extend({
      template: '<div>注册组件</div>'
    });

    // 路由实例
    var router = new VueRouter({
      routes: [
        { path: '/', redirect: '/account/login' }, // 使用 redirect 实现路由重定向
        {
          path: '/account',
          component: account,
          children: [ // 通过 children 数组属性,来实现路由的嵌套
            { path: 'login', component: login }, // 注意,子路由的开头位置,不要加 / 路径符
            { path: 'register', component: register }
          ]
        }
      ]
    });

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      components: {
        account
      },
      router: router
    });
  </script>

命名视图实现经典布局

<!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.5.9.js"></script>
  <script src="./lib/vue-router-v3.0.1.js"></script>
  <style>
    html,
    body,
    h1 {
      margin: 0;
      padding: 0;
      font-size: 20px;
    }

    .header {
      height: 120px;
      background-color: darkcyan;
    }

    .container {
      height: 400px;
      display: flex;
    }

    .sidebar {
      background-color: orange;
      flex: 2;
    }

    .content {
      background-color: pink;
      flex: 10;
    }

    .footer {
      background-color: black;
      color: white;
      height: 100px;
    }
  </style>
</head>

<body>
  <div id="app">
    <!-- 路由的容器 -->
    <router-view name="top"></router-view>
    <div class="container">
      <router-view name="left"></router-view>
      <router-view name="right"></router-view>
    </div>
    <router-view name="bottom"></router-view>
  </div>

  <script>

    const header = {
      template: `<h1 class="header">头部区域</h1>`
    }
    const sidebar = {
      template: `<h1 class="sidebar">左侧侧边栏</h1>`
    }
    const content = {
      template: `<h1 class="content">主体内容区域</h1>`
    }
    const footer = {
      template: `<h1 class="footer">尾部</h1>`
    }

    const router = new VueRouter({
      routes: [
        // { path: '/', component: header }
        {
          path: '/', components: {
            //     组件名称 :  组件对象
            'top': header,
            'left': sidebar,
            'right': content,
            'bottom': footer
          }
        }
      ]
    })

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      router
    });
  </script>
</body>

</html>

watch属性的使用

考虑一个问题:想要实现 两个文本框的内容改变,则全名的文本框中的值也跟着改变;(用以前的知识如何实现???)

  1. 场景一:watch监听data中属性的改变:
    <div id="app">
    <input type="text" v-model="firstName"> +
    <input type="text" v-model="lastName"> =
    <span>{{fullName}}</span>
    </div>
    
    <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        firstName: 'jack',
        lastName: 'chen',
        fullName: 'jack - chen'
      },
      methods: {},
      watch: {
        'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据
          this.fullName = newVal + ' - ' + this.lastName;
        },
        'lastName': function (newVal, oldVal) {
          this.fullName = this.firstName + ' - ' + newVal;
        }
      }
    });
    </script>
  2. 场景二:watch监听路由对象的改变:
    <div id="app">
    <router-link to="/login">登录</router-link>
    <router-link to="/register">注册</router-link>
    
    <router-view></router-view>
    </div>
    
    <script>
    var login = Vue.extend({
      template: '<h1>登录组件</h1>'
    });
    
    var register = Vue.extend({
      template: '<h1>注册组件</h1>'
    });
    
    var router = new VueRouter({
      routes: [
        { path: "/login", component: login },
        { path: "/register", component: register }
      ]
    });
    
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      router: router,
      watch: {
        '$route': function (newVal, oldVal) {
          if (newVal.path === '/login') {
            console.log('这是登录组件');
          }
        }
      }
    });
    </script>

computed计算属性的使用

  1. 默认只有getter的计算属性:
    <div id="app">
    <input type="text" v-model="firstName"> +
    <input type="text" v-model="lastName"> =
    <span>{{ fullName }}</span>
    </div>
    
    <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        firstName: 'jack',
        lastName: 'chen'
      },
      methods: {},
      computed: { // 计算属性; 特点:当计算属性中所以来的任何一个 data 属性改变之后,都会重新触发 本计算属性 的重新计算,从而更新 fullName 的值
        fullName() {
          return this.firstName + ' - ' + this.lastName;
        }
      }
    });
    </script>
  2. 定义有gettersetter的计算属性:
    <div id="app">
    <input type="text" v-model="firstName">
    <input type="text" v-model="lastName">
    <!-- 点击按钮重新为 计算属性 fullName 赋值 -->
    <input type="button" value="修改fullName" @click="changeName">
    
    <span>{{fullName}}</span>
    </div>
    
    <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        firstName: 'jack',
        lastName: 'chen'
      },
      methods: {
        changeName() {
          this.fullName = 'TOM - chen2';
        }
      },
      computed: {
        fullName: {
          get: function () {
            return this.firstName + ' - ' + this.lastName;
          },
          set: function (newVal) {
            var parts = newVal.split(' - ');
            this.firstName = parts[0];
            this.lastName = parts[1];
          }
        }
      }
    });
    </script>

watchcomputedmethods之间的对比

  1. computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  2. methods方法表示一个具体的操作,主要书写业务逻辑;
  3. watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computedmethods的结合体;
posted @ 2021-07-04 15:16  yescctv6  阅读(85)  评论(0编辑  收藏  举报