vue2 基础知识总结

206 阅读11分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

vue2 基础知识总结

介绍

Vue 框架的特点 模板渲染:基于 html 的模板语法,学习成本低。 响应式的更新机制:数据改变之后,视图会自动刷新。【重要】 渐进式框架 组件化/模块化 轻量:开启 gzip 压缩后,可以达到 20kb 大小。(React 达到 35kb,AngularJS 达到 60kb)。

npm install -g @vue/cli
vue create my-app
cd my-app
npm run serve
系统指令
1、插值表达式 {{}}

数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值。例如: Message: {{ msg }} Mustache 标签将会被替代为对应数据对象上 msg 属性(msg 定义在 data 对象中)的值。 无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会自动更新。

{{}}对JavaScript 表达式支持,例如:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ name == 'smyhvae' ? 'true' : 'false' }}
{{ message.split('').reverse().join('') }}

但是有个限制就是,每个绑定都只能包含单个表达式,如下表达式无效:

{{ var a = 1 }}

{{ if (ok) { return message } }}

2、v-cloak:保持和元素实例的关联,直到结束编译后自动消失。

v-cloak 指令和 CSS 规则一起用的时候,能够解决差值表达式闪烁的问题(即:可以隐藏未编译的标签直到实例准备完毕)。

就拿上一段代码来举例,比如说,{{name}}这个内容,在网速很慢的情况下,一开始会直接显示{{name}}这个内容,等网络加载完成了,才会显示 smyhvae。那这个闪烁的问题该怎么解决呢?

解决办法是:通过 v-cloak 隐藏{{name}}这个内容,当加载完毕后,再显示出来。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>

    /*2、在样式表里设置:只要是有 v-cloak 属性的标签,我都让它隐藏。
    直到 Vue实例化完毕以后,v-cloak 会自动消失,那么对应的css样式就会失去作用,最终将span中的内容呈现给用户 */
    [v-cloak] {
      display: none;
    }
  </style>
</head>

<body>
  <div id="app">
    <!-- 1、给 span 标签添加 v-cloak 属性 -->
    <span v-cloak>{{name}}</span>

  </div>
</body>

<script src="vue2.5.16.js"></script>
<script>
  new Vue({
    el: '#app',
    data: {
      name: 'smyhvae'
    }
  });
</script>

</html>
3、v-text

v-text v-text 可以将一个变量的值渲染到指定的元素中。例如:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <!--vue的版本:2.5.15-->
  <script src="vue.js"></script>
</head>

<body>
  <div id="div1">
    <span v-text="name"></span>
  </div>
</body>

<script>
  new Vue({
    el: '#div1',
    data: {
      name: 'hello smyhvae'
    }
  });
</script>

</html>

区别 1: v-text 没有闪烁的问题,因为它是放在属性里的。 区别 2 :插值表达式只会替换自己的这个占位符,并不会把整个元素的内容清空。v-text 会覆盖元素中原本的内容。

v-html v-text 是纯文本,而 v-html 会被解析成 html 元素。 注意:使用 v-html 渲染数据可能会非常危险,因为它很容易导致 XSS(跨站脚本) 攻击,使用的时候请谨慎,能够使用{{}}或者 v-text 实现的不要使用 v-html。

v-bind:属性绑定机制 v-bind:用于绑定属性。 上方代码中,给属性加了 v-bind 之后,属性值里的整体内容是表达式,属性值里的 imageSrc 和 size 是 Vue 实例里面的变量。 也就是说, v-bind 的属性值里,可以写合法的 js 表达式。

v-on:事件绑定机制 v-on:click:点击事件

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <!--vue的版本:2.5.15-->
  <script src="vue.js"></script>
</head>

<body>
  <!--这个div区域就是MVVM中的 View-->
  <div id="div1">
    <!-- 给button节点绑定按钮的点击事件 -->
    {{name}}
    <button v-on:click="change">改变name的值</button>
  </div>


</body>

<script>
  //new出来的对象就是MVVM中的 View Module
  var myVue = new Vue({
    el: '#div1', //当前vue对象将接管上面的div区域
    data: { //data就是MVVM中的 module
      name: 'smyhvae'
    },

    //注意,下方这个 `methods` 是Vue中定义方法的关键字,不能改
    //这个 methods 属性中定义了当前Vue实例所有可用的方法
    methods: {
      change: function() { //上面的button按钮的点击事件
        this.name += '1';
      }
    }
  });
</script>

</html>

上方代码中,我们给 button 按钮绑定了点击事件。注意,这个 button 标签要写在 div 区域里(否则点击事件不生效),因为下方的 View module 接管的是 div 区域。

v-on 的简写形式

例如: 改变 name 的值 可以简写成: <button @click="change">改变 name 的值

v-on 提供了 click 事件,也提供了一些其他的事件。

v-on:click

v-on:keydown

v-on:keyup

v-on:mousedown

v-on:mouseover

v-on:submit v-model:双向数据绑定 重点:双向数据绑定,只能用于表单元素,或者用于自定义组件。 之前的文章里,我们通过 v-bind,给<input >标签绑定了 data 对象里的 name 属性。当 data 里的 name 的值发生改变时,<input >标签里的内容会自动更新。 可我现在要做的是:我在<input >标签里修改内容,要求 data 里的 name 的值自动更新。从而实现双向数据绑定。该怎么做呢?这就可以利用 v-model 这个属性。

区别: v-bind:只能实现数据的单向绑定,从 M 自动绑定到 V。 v-model:只有 v-model 才能实现双向数据绑定。注意,v-model 后面不需要跟冒号,

注意:v-model 只能运用在表单元素中,或者用于自定义组件。常见的表单元素包括:input(radio, text, address, email....) 、select、checkbox 、textarea。

直接使用对象 写法四:直接使用对象。代码如下:

vue 的写法 4:直接使用对象 在为 class 使用 v-bind 绑定 对象的时候,对象的属性是类名。由于 对象的属性名可带引号,也可不带引号,所以 这里我没写引号; 属性的值 是一个标识符 <h1 :class="{style1:true, style2:false}">我是 smyhvae,hello</h1>

上方代码的意思是,给<h1>标签使用样式 style1,不使用样式 style2。注意:

1、既然 class 样式名是放在对象中的,这个样式名不能有中划线,比如说,写成:class="{my-red:true, my-active:false},是会报错的。

vue 中通过属性绑定为元素设置 style 行内样式 注意,是行内样式(即内联样式)。 写法一 写法一:直接在元素上通过 :style 的形式,书写样式对象。 例如:

    <h1 :style="{color: 'red', 'font-size': '20px'}">我是hellosmyhvae</h1>

写法二 写法二:将样式对象,定义到 data 中,并直接引用到 :style 中。 也就是说,把写法一的代码改进一下。代码如下:

<body>
    <div id="app">
        <h1 :style="styleObj">我是hello,smyhvae</h1>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                styleObj: { color: 'red', 'font-size': '20px' }
            }
        });
    </script>

</body>

写法三 写法二只用到了一组样式。如果想定义多组样式,可以用写法三。 写法三:在 :style 中通过数组,引用多个 data 上的样式对象。 代码如下:

<body>
    <div id="app">
        <h1 :style="[ styleObj1, styleObj2 ]">我是hello,smyhvae</h1>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                styleObj1: { color: 'red', 'font-size': '20px' },
                styleObj2: { 'font-style': 'italic' }
            }
        });
    </script>

</body>

方式一:普通数组的遍历 针对下面这样的数组:

<script>
  new Vue({
    el: '#app',
    data: {
      arr1: [2, 5, 3, 1, 1],
    }
  });
</script>

将数组中的值赋给 li:

<li v-for="item in arr1">{{item}}</li> 将数组中的值和 index 赋给 li: 括号里如果写两个参数:第一个参数代表值,第二个参数代表 index 索引 <li v-for="(item,index) in arr1">值:{{item}} --- 索引:{{index}}</li>

obj1 对象的数据赋值给 li,写法如下:

<body>
  <div id="app">
    <ul>
      <!-- 括号里如果写两个参数:则第一个参数代表value,第二个参数代表key -->
      <li v-for="(value,key) in obj1">值:{{value}} --- 键:{{key}} </li>

      <h3>---分隔线---</h3>

      <!-- 括号里如果写三个参数:则第一个参数代表value,第二个参数代表key,第三个参数代表index -->
      <li v-for="(value,key,index) in obj1">值:{{value}} --- 键:{{key}} --- index:{{index}} </li>
    </ul>

  </div>
</body>

v-show:设置元素的显示和隐藏(在元素上添加/移除 style="display:none"属性)

作用:根据表达式的真假条件,来切换元素的 display 属性。如果为 false,则在元素上添加 display:none 属性;否则移除 display:none 属性。

v-if 和 v-show 的区别 v-if 和 v-show 都能够实现对一个元素的隐藏和显示操作。 区别: v-if:每次都会重新添加/删除 DOM 元素 v-show:每次不会重新进行 DOM 的添加/删除操作,只是在这个元素上添加/移除 style="display:none"属性,表示节点的显示和隐藏。 优缺点: v-if:有较高的切换性能消耗。这个很好理解,毕竟每次都要进行 dom 的添加/删除操作。 v-show:有较高的初始渲染消耗。也就是说,即使一开始 v-show="false",该节点也会被创建,只是隐藏起来了。而 v-if="false"的节点,根本就不会被创建。 总结: 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if

v-on

v-on 提供了很多事件修饰符来辅助实现一些功能。事件修饰符有如下: .stop 阻止冒泡。本质是调用 event.stopPropagation()。 .prevent 阻止默认事件(默认行为)。本质是调用 event.preventDefault()。 .capture 添加事件监听器时,使用捕获的方式(也就是说,事件采用捕获的方式,而不是采用冒泡的方式)。 .self 只有当事件在该元素本身(比如不是子元素)触发时,才会触发回调。 .once 事件只触发一次。 .{keyCode | keyAlias} 只当事件是从侦听器绑定的元素本身触发时,才触发回调。 .native 监听组件根元素的原生事件。 PS:一个事件,允许同时使用多个事件修饰符。

自定义过滤器

Vue.filter(‘过滤器的名称’, 具体的过滤器函数)中的第一个参数指的就是过滤器的名称(必须和管道符后面的名称完全一致),第二个参数是具体的过滤器函数 过滤器函数 function 中,第一个参数指的管道符前面的 msg。 replace()方法是用来做字符串的替换的。第一个参数如果只写成单纯,那么就会只修改 msg 中的第一个单纯字样。所以这里就用正则去匹配 msg 中所有的单纯字样。 最终,完整版代码如下:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 通过 过滤器 msgFormat 对 msg 进行过滤-->
        <p>{{ msg | msgFormat }}</p>
    </div>

    <script>
        // 定义一个 Vue 全局的过滤器,名字叫做  msgFormat
        Vue.filter('msgFormat', function (myMsg) {
            // 字符串的  replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
            //将 myMsg 中的所有`单纯`字样,修改为`邪恶`
            return myMsg.replace(/单纯/g, '邪恶')
        })

        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人'
            },
            methods: {}
        });
    </script>
</body>

</html>

对 msg 同时使用多个过滤器。例如:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 通过 两个过滤器(msgFormat、myFilter2)对 msg 进行过滤-->
        <!-- 将 msg 交给第一个过滤器来处理,然后将处理的结果交给第二个过滤器来处理-->
        <p>{{ msg | msgFormat('【牛x】', '【参数arg3】') | myFilter2}}</p>

    </div>

    <script>
        // 定义一个 Vue 全局的过滤器,名字叫做  msgFormat
        Vue.filter('msgFormat', function (myMsg, arg2, arg3) {
            // 字符串的  replace 方法:第一个参数,除了可写一个 字符串之外,还可以定义一个正则;第二个参数代表要替换为 xxx
            //将 myMsg 中的所有`单纯`字样,修改为`arg2 + arg3`
            return myMsg.replace(/单纯/g, arg2 + arg3)
        })

        //定义第二个全局过滤器
        Vue.filter('myFilter2', function (myMsg) {
            //在字符串 msg 的最后面加上【后缀】
            return myMsg + '【后缀】'
        })

        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人'
            },
            methods: {}
        });
    </script>
</body>

</html>

自定义私有过滤器 私有过滤器:在某一个 vue 对象内部定义的过滤器称之为私有过滤器。这种过滤器只有在当前 vue 对象的 el 指定的监管区域有用。 举例:日期格式化

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        {{ time }}
        <br />
        {{ time | datefmt }}
    </div>

</body>
<script>
    new Vue({
        el: '#app',
        data: {
            time: new Date()
        },
        //在某一个vue对象内部定义的过滤器称之为私有过滤器,
        //这种过滤器只有在当前vue对象el指定的监管的区域有用
        filters: {
            // input是自定义过滤器的默认参数,input的值永远都是取自于 | 左边的内容
            datefmt: function (input) {
                // 定义过滤器的内容:将input的值格式化成 yyyy-MM-dd 字符串输出
                var res = '';
                var year = input.getFullYear();
                var month = input.getMonth() + 1;
                var day = input.getDate();

                res = year + '-' + month + '-' + day;

                return res;
            }
        }
    });
</script>
</html>
生命周期

vue 实例的生命周期:从 Vue 实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期。 生命周期钩子:就是生命周期事件的别名而已。 1、创建期间的生命周期函数 beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性 created:实例已经在内存中创建 OK,此时 data 和 methods 已经创建 OK,此时还没有开始 编译模板。我们可以在这里进行 Ajax 请求。 beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中 mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示。(mounted 之后,表示真实 DOM 渲染完了,可以操作 DOM 了) 2、运行期间的生命周期函数 beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染 DOM 节点 updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了。 PS:数据发生变化时,会触发这两个方法。不过,我们一般用 watch 来做。 3、销毁期间的生命周期函数 beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。 destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 PS:可以在 beforeDestroy 里清除定时器、或清除事件绑定。

ajax

vue.js 文件向 Windows 对象暴露了 Vue 这个关键词;vue-resource.js 向 Vue 身上挂载了 this.http这个属性。于是,我们可以直接写this.http这个属性。于是,我们可以直接写this.http.get 或者 this.http.post或者this.http.post或者this.http.jsonp 来调用。 vue-resource 发送 Ajax 请求 常见的数据请求类型包括:get、post、jsonp。下面我们分别讲一讲。 get 请求 格式举例: this.$http.get(url) .then(function (result) { // 当发起 get 请求之后,通过 .then 来设置成功的回调函数 console.log(result.body); // response.body 就是服务器返回的成功的数据 var result = result.body; }, function (err) { //err 是异常数据 });

获取到的 response.body 就是要获取的数据,但直接打印出来是 object,所以要记得转成 string。

动画
<!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>
    <style>
        /* 自定义第一组样式,来控制 transition 内部的元素实现动画 */

        /* 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;
        }


        /* 自定义第二组样式,来控制 transition 内部的元素实现动画。这次,我们通过自己起的别名`name`来作为指令 */

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

        .my-enter-active,
        .my-leave-active {
            transition: all 1s ease;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- 第一组 -->
        <input type="button" value="toggle" @click="flag=!flag">
        <!-- 使用 transition 元素,把 需要被动画控制的元素 h3,包裹起来 -->
        <!-- transition 元素,是 Vue 官方提供的 -->
        <transition>
            <h3 v-if="flag">这是一个H3</h3>
        </transition>

        <hr>

        <!-- 第二组 -->
        <input type="button" value="toggle2" @click="flag2=!flag2">
        <!-- 使用 transition 元素,把 需要被动画控制的元素 h6,包裹起来 -->
        <!-- transition 元素,是 Vue 官方提供的 -->
        <!-- 【重点】在这里,我们给这个transition定义一个别名,叫`name`,然后,我们就可以通过 `.my-enter`等 来定义动画的样式【重要】 -->
        <transition name="my">
            <h6 v-if="flag2">这是一个H6</h6>
        </transition>
    </div>

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

</html>

使用第三方 animate.css 类库实现动画

animate.css 网址:

官方网站:daneden.github.io/animate.css… 代码举例:

下面的代码中,我们使用 animate.css 提供的 bounceIn、bounceOut 这两个类来做入场、离场的动画。代码如下:

<!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="vue2.5.16.js"></script>
    <link rel="stylesheet" href="animate3.6.0.css">
    <!-- 入场 bounceIn    离场 bounceOut -->
</head>

<body>
    <div id="app">
        <input type="button" value="toggle" @click="flag=!flag">
        <!-- 需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->
        <transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
            <h3 v-if="flag">这是一个H3</h3>
        </transition>

    </div>

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

</html>

注意 1:enter-active-class 和 leave-active-class 这两个类名是 Vue 动画里的关键词,不能写成自己随意起的类名。

注意 2:bounceIn、bounceOut 这两个类不能直接使用,要在前面加上 animated 这个类;否则动画是不会生效的。当然,上面的代码中,我们还可以把 class = animated 这个代码移到<h3>标签里,效果是一样的,如下:

         需求: 点击按钮,让 h3 显示,再点击,让 h3 隐藏
        <transition enter-active-class="bounceIn" leave-active-class="bounceOut">
            <h3 v-if="flag" class="animated">这是一个H3</h3>
        </transition>

点击按钮后,让小球进行移动。完整代码如下:

<!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="vue2.5.16.js"></script>
    <style>
        .ball {
            width: 15px;
            height: 15px;
            border-radius: 50%;
            background-color: red;
        }
    </style>
</head>

<body>
    <div id="app">
        <input type="button" value="加入购物车" @click="flag=!flag">
        <!-- 1. 使用 transition 元素把 小球包裹起来 -->
        <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
            <div class="ball" v-show="flag"></div>
        </transition>
    </div>

    <script>

        var vm = new Vue({
            el: '#app',
            data: {
                flag: false
            },
            methods: {
                // 注意: 动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
                // 我们可以认为 , el 是通过 document.getElementById('') 方式获取到的原生JS DOM对象
                beforeEnter(el) {
                    // beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
                    // 设置小球开始动画之前的 起始位置
                    el.style.transform = "translate(0, 0)"   // smyhvae提示:一开始的时候,让小球处于(0,0)的位置
                },
                enter(el, done) {
                    // 【注意1】el.offsetWidth 这句话,没有实际的作用,但是,如果不写,出不来动画效果。可以认为 el.offsetWidth 会强制动画刷新
                    el.offsetWidth
                    // enter 表示动画 开始之后的样式,这里,可以设置小球完成动画之后的,结束状态
                    el.style.transform = "translate(150px, 300px)" // smyhvae 提示:让小球从(0,0)移动到 (150px, 300px)
                    el.style.transition = 'all 1s ease'

                    // 【注意2】这里的 done, 起始就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
                    done()
                },
                afterEnter(el) {
                    // 动画完成之后,会调用 afterEnter
                    // console.log('ok')
                    // 动画结束后,让小球消失(直接让 flag 取反即可)
                    this.flag = !this.flag  // 因为最开始的时候,小球就是处于消失的状态,这行代码可以让小球的动画重新开始
                }
            }
        });
    </script>
</body>

</html>

如果我们用把 li 包裹起来,就会让所有的 li 都具备了动画,这显然是不可取的。 那该怎么做呢?这里我们就可以用 transition-group 进行包裹。 代码举例 1:点击添加按钮后,给新增的 item 加个动画

<!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="vue2.5.16.js"></script>
    <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.8s ease;  /*鼠标悬停时,出现背景色。让这个背景色的出现,也加一个淡入的动画*/
        }

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

        .v-enter-active,
        .v-leave-active {
            transition: all 0.6s ease;
        }
    </style>
</head>

<body>
    <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 属性 -->
        <transition-group>
            <li v-for="(item, i) in list" :key="item.id">
                {{item.id}} --- {{item.name}}
            </li>
        </transition-group>
        <!-- </ul> -->

    </div>

    <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                id: '',
                name: '',
                list: [
                    { id: 1, name: '赵高' },
                    { id: 2, name: '秦桧' },
                    { id: 3, name: '严嵩' },
                    { id: 4, name: '魏忠贤' }
                ]
            },
            methods: {
                add() {
                    this.list.push({ id: this.id, name: this.name })
                    this.id = this.name = ''
                }
            }
        });
    </script>
</body>
</html>
组件定义和注册

组件 Component 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。 全局组件的定义和注册有三种方式,我们接下来讲一讲。 写法一 写法一:使用 Vue.extend 方法定义组件,使用 Vue.component 方法注册组件。 代码举例:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 如果要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中,即可 -->
        <account> </account>
    </div>

    <script>
        //第一步:使用 Vue.extend 定义组件
        var myAccount = Vue.extend({
            template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>' // 通过 template 属性,指定了组件要展示的HTML结构。template 是 Vue 中的关键字,不能改。
        });
        //第二步:使用 Vue.component 注册组件
        // Vue.component('组件的名称', 创建出来的组件模板对象)
        Vue.component('account', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

写法二:Vue.component 方法定义、注册组件(一步到位)。 代码如下:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <account> </account>
    </div>

    <script>

        //定义、注册组件:第一个参数是组件的名称(标签名),第二个参数是组件的定义
        Vue.component('account', {
            template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>'   // template 是 Vue 中的关键字,不能改。
        });

        new Vue({
            el: '#app'
        });
    </script>
</body>

</html>

当然,我们还可以把模板的定义存放在<template>标签中,这样的话,模板里的 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="vue2.5.16.js"></script>
</head>

<body>

    <!-- 定义模板 -->
    <template id="loginTmp">
        <h3>这是私有的login组件</h3>
    </template>

    <div id="app">
        <!-- 调用Vue实例内部的私有组件 -->
        <my-login></my-login>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {},
            components: { // 定义、注册Vue实例内部的私有组件
                myLogin: {
                    template: '#loginTmp'
                }
            }
        });
    </script>
</body>

</html>

使用 Vue 提供的标签实现组件切换

上面的例子中,我们是通过 flag 的值来进行组件的切换。但是,flag 的值只可能有两种情况,也就是说,v-if 和 v-else 只能进行两个组件之间的切换。

那如何实现三个甚至三个以上的组件切换呢?这里,我们可以用到 Vue 提供的标签。

我们先来看一下标签的用法。

基于上面的代码,如果我想让 login 组件显示出来,借助标签可以这样做: 实现组件切换的完整代码:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 点击按钮后,设置变量`comName`为不同的值,代表着后面的component里显示不同的组件 -->
        <a href="" @click.prevent="comName='login'">登录</a>
        <a href="" @click.prevent="comName='register'">注册</a>

        <!-- Vue提供了 component ,来展示对应名称的组件 -->
        <!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
        <!-- 此处的`comName`是变量,变量值为组件名称 -->
        <component :is="comName"></component>

    </div>

    <script>
        // 组件名称是 字符串
        Vue.component('login', {
            template: '<h3>登录组件</h3>'
        })

        Vue.component('register', {
            template: '<h3>注册组件</h3>'
        })

        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: {
                comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
            },
            methods: {}
        });
    </script>
</body>

</html>
组件间传值

需要注意的是,子组件不能直接使用父组件中的数据。父组件可以通过 props 属性向子组件传值。

子组件中,data 中的数据和 props 中的数据的区别: 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上。props 中的数据,都是通过 父组件 传递给子组件的。 data 中的数据是可读可写的;props 中的属性只是可读的,无法重新赋值,重新赋值会报错(也就是说,子组件不要直接去修改父组件中的数据)。

父组件将方法传递给子组件 父组件通过事件绑定机制,将父组件的方法传递给子组件

代码举例:

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <!-- 父组件向子组件 传递 方法,是通过 事件绑定机制; v-on。当我们自定义了 一个 事件属性 parent-show(这个地方不能用驼峰命名)之后,-->
        <!-- 那么,子组件就能够,通过 emit 来调用 传递进去的 这个 方法了 -->
        <!-- 【第一步】。意思是说,`show`是父组件的方法名,`parent-show`是自定义的时间属性,稍后要在子组件中用到 -->
        <component1 @parent-show='show'></component1>
    </div>

    <!-- 定义子组件的模板 -->
    <template id="myTemplate">
        <!-- 【第二步】按照正常的写法来:点击按钮,调用子组件的方法 -->
        <div @click="childClick">我是子组件,点击调用父组件的方法</div>
    </template>

    <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: { //父组件的data
                // msg: '父组件中的数据'
            },
            methods: {
                show: function () { // 定义父组件的show方法
                    console.log('父组件提供的方法');
                }
            },
            components: {
                component1: { //将子组件的名称定义为 component1
                    template: '#myTemplate',
                    data() { // 子组件的data
                        return {
                            // content: '子组件私有的数据 content'
                        }
                    },
                    props: [''],
                    directives: {},
                    filters: {},
                    components: {},
                    methods: {
                        childClick() {
                            // 当点击子组件的按钮时,如何 拿到 父组件传递过来的 func 方法,并调用这个方法???
                            //  emit 英文原意: 是触发,调用、发射。意思是,触发父组件的方法
                            // 【第三步】 在子组件的方法中,通过 emit 触发父组件的方法
                            this.$emit('parent-show');
                        }
                    }
                }
            }
        });
    </script>
</body>

</html>

如果要实现子组件向父组件传值,代码是类似的,我们只需要在子组件通过 emit 触发父组件的方法时,把子组件的参数带出去就可以了。代码如下。

代码举例 1:(将子组件中的常量传递给父组件)

<!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="vue2.5.16.js"></script>
</head>

<body>
    <div id="app">
        <component1 @parent-show='show'></component1>
    </div>

    <!-- 定义子组件的模板 -->
    <template id="myTemplate">
        <h2 @click="childClick">我是子组件,点击调用父组件的方法</h2>
    </template>

    <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
            el: '#app',
            data: { //父组件的data
                // msg: '父组件中的数据'
            },
            methods: { // 定义父组件的方法
                show: function (arg1, arg2) { //【第二步】父组件里放两个参数,这个两个参数就代表着子组件中的`child 123`、`child 789`
                    console.log('父组件提供的方法');
                    console.log('打印子组件传递过来的参数。参数一:' + arg1 + ',参数二:'+ arg2);
                }
            },
            components: {
                component1: { //将子组件的名称定义为 component1
                    template: '#myTemplate',
                    data() { // 子组件的data
                        return {
                            // content: '子组件私有的数据 content'
                        }
                    },
                    props: [''],
                    directives: {},
                    filters: {},
                    components: {},
                    methods: {
                        childClick() {
                            // 子组件如果要给父组件传递参数,在触发 emit 的时候,通过参数的形式带出去就可以了
                            // 【第一步】在子组件里,我们带两个参数出去,传给父组件
                            this.$emit('parent-show', 'child 123', 'child 789');
                        }
                    }
                }
            }
        });
    </script>
</body>

</html>
Vue-router

后端路由

对于普通的网站,所有的超链接都是 URL 地址,所有的 URL 地址都对应服务器上对应的资源。

当前端输入 url 请求资源时,服务器会监听到是什么 url 地址,那后端会返回什么样的资源呢?后端这个处理的过程就是通过路由来分发的。

总结:后端路由,就是把所有 url 地址都对应到服务器的资源,这个对应关系就是路由。

前端路由

对于单页面应用程序来说,主要通过 URL 中的 hash(url 地址中的#号)来实现不同页面之间的切换。

同时,hash 有一个特点:HTTP 请求中不会包含 hash 相关的内容。所以,单页面程序中的页面跳转主要用 hash 实现。

总结:在单页应用程序中,这种通过 hash 改变来切换页面的方式,称作前端路由(区别于后端路由)。

ref

基本用法,本页面获取 dom 元素

<template>
  <div id="app">
    <div ref="testDom">11111</div>
    <button @click="getTest">获取test节点</button>
  </div>
</template>

<script>
export default {
  methods: {
    getTest() {
      console.log(this.$refs.testDom)
    }
  }
};
</script>

获取子组件中的 data

子组件

<template>
  <div>
      {{ msg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world"
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <HelloWorld ref="hello"/>
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      console.log(this.$refs.hello.msg)
    }
  }
};
</script>

调用子组件中的方法

子组件

<template>
  <div>
  </div>
</template>

<script>
export default {
  methods: {
    open() {
      console.log("调用到了")
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <HelloWorld ref="hello"/>
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      this.$refs.hello.open();
    }
  }
};
</script>

。子组件调用父组件方法

子组件

<template>
  <div>
</div>
</template>

<script>
export default {
  methods: {
    open() {
      console.log("调用了");
      //  调用父组件方法
      this.$emit("refreshData");
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <HelloWorld ref="hello" @refreshData="getData"/>
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      this.$refs.hello.open()
    },
    getData() {
      console.log('111111')
    }
  }
};
</script>
插槽

当组件渲染的时候, 将会被替换为“Your Profile”。插槽内可以包含任何模板代码,包括 HTML: 匿名插槽 直接替换标签内的内容 具名插槽

<template>
     <header>
           <slot name="header">test<slot>
     </header>
<template>
<p slot="header">
    123 //标签内的内容将替换header里的slot内容
</p>

作用域插槽 1、当我们希望 li 的样式由外部使用组件的地方定义,因为可能会有多种地方需要使用该组件,但希望样式不一样,这个时候需要使用作用域插槽 2、 父组件中使用了<template>元素,而且包含 scope="slotProps", 3、 在子组件模板中,<slot>元素上有一个类似 props 传递数据给组件的写法 msg="xxx", ### 插槽可以提供一个默认内容,如果如果父组件没有为这个插槽提供了内容,会显示默认的内容。 如果父组件为这个插槽提供了内容,则默认的内容会被替换掉 slotProps 在这里只是临时变量。

总结

以上就是 vue2 基础知识总结。 开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情