Vue入门教程

1.简介

Vue是一套用于构建用户界面的渐进式框架, 发布于2014年2月。与其它大型框架不同的是, Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层, 不仅易于上手, 还便于与第三方库(如:vue-router,vue-resource,vue x) 或既有项目整合。

1.1 vue的实现模式

MVVM模式

  • Model:模型层, 在这里表示JavaScript对象
  • View:视图层, 在这里表示DOM(HTML操作的元素)
  • ViewModel:连接视图和数据的中间件, Vue.js就是MVVM中的View Model层的实现者

在MVVM架构中, 是不允许数据和视图直接通信的, 只能通过ViewModel来通信, 而View Model就是定义了一个Observer观察者

  • ViewModel能够观察到数据的变化, 并对视图对应的内容进行更新
  • ViewModel能够监听到视图的变化, 并能够通知数据发生改变

至此, 我们就明白了, Vue.js就是一个MV VM的实现者, 他的核心就是实现了DOM监听与数据绑定

1.2 vue的优点 

  • 轻量级, 体积小是一个重要指标。Vue.js压缩后有只有20多kb(Angular压缩后56kb+,React压缩后44kb+)
  • 移动优先。更适合移动端, 比如移动端的Touch事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了Angular(模块化) 和React(虚拟DOM) 的长处, 并拥有自己独特的功能,如:计算属性
  • 开源,社区活跃度高

2.HelloVue

首先在idea中下载vue.js插件

注意:Vue不支持IE 8及以下版本, 因为Vue使用了IE 8无法模拟的ECMAScript 5特性。但它支持所有兼容ECMAScript 5的浏览器。

2.1 第一个vue程序

1)下载地址

  • 开发版本
  • CDN
    • <script src=“https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js”></script>
    • <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

2) 代码编写 

1.创建一个html文件 demo01.html

2.引入 vue.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

</body>
</html>

3.创建一个vue实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    //Model : 数据层
    var vm = new Vue({
       el: "#app",
        data:{
           message: "hello,vue!"
        }
    });
</script>


</body>
</html>

说明: 

  • el: 'vue':绑定元素的ID
  • data:{message:'Hello Vue!'}:数据对象中有一个名为message的属性,并设置了初始值 Hello Vue!

4.将数据绑定页面元素 

只需要在绑定的元素中使用双花括号将Vue创建的名为message属性包裹起来, 即可实现数据绑定功能, 也就实现了View Model层所需的效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>狂神说Java</h1>
<!-- view : 视图层 -->
<div id="app">
    <h1>{{message}}</h1>
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    //Model : 数据层
    var vm = new Vue({
       el: "#app",
        data:{
           message: "hello,vue!"
        }
    });
</script>


</body>
</html>

 5.这时可以直接在页面中修改我们的message属性的值,页面也会随之变化

语句为 vm.message='xxx';

3. Vue的基础语法指令 

3.1  v-bind(单向绑定)

我们已经成功创建了第一个Vue应用!看起来这跟渲染一个字符串模板非常类似, 但是Vue在背后做了大量工作。现在数据和DOM已经被建立了关联, 所有东西都是响应式的。我们在控制台操作对象属性,界面可以实时更新!
我们还可以使用v-bind来绑定元素特性!

简写形式:    :value="xxx"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>狂神说Java</h1>
<!-- view : 视图层 -->
<div id="app">
    <h1>{{message}}</h1>

    <span v-bind:title="message">
        鼠标悬停几秒钟查看此处动态绑定的提示信息!
    </span>
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    //Model : 数据层
    var vm = new Vue({
       el: "#app",
        data:{
           message: "hello,vue!"
        }
    });
</script>


</body>
</html>

你看到的v-bind等被称为指令。指令带有前缀v以表示它们是Vue提供的特殊特性。它们会在渲染的DOM上应用特殊的响应式行为,该指令的意思是:“将这个元素节点的title特性和Vue实例的message属性保持一致”。如果我们在页面中修改了message属性的值,title绑定的message属性的值也会随之改变。

3.2 v-model(双向绑定) 

当对data数据进行更改时,View层也会进行改变,也就是说我们的视图页面也会实时更改

<input v-model:value="name" /> 

v-model只能用在表单类元素中(输入类元素)

也就是说,有一个属性是value的元素

v-model:value='xxx'可以简写成v-model='xxx'

3.3. 事件处理

  • v-if
  • v-else
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <h1 v-if="ok">yes</h1>
    <h2 v-else>no</h2>
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
       el: "#app",
       data:{
           ok: true
       }
    });
</script>


</body>
</html>

测试:
1.在浏览器上运行,打开控制台!
2.在控制台输入vm.ok=false然后回车,你会发现浏览器中显示的内容会直接变成NO
注:使用v-*属性绑定数据是不需要双花括号包裹的

v-else-if

  • v-if
  • v-else-if
  • v-else
    注:=== 三个等号在JS中表示绝对等于(就是数据与类型都要相等) 的代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <h1 v-if="type === 'A'">A</h1>
    <h1 v-else-if="type === 'B'">B</h1>
    <h1 v-else-if="type === 'C'">C</h1>

</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        data:{
            type: 'A'
        }
    });
</script>

</body>
</html>

3.3.1  v-on

v-on监听事件
emsp;事件有Vue的事件、和前端页面本身的一些事件!我们这里的click是vue的事件, 可以绑定到Vue中的methods中的方法事件!

创建一个html页面,当我们打开页面点击对应按钮时,就会调用对应的方法实现点击事件 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>

</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <h2>欢迎来到{{name}}学习先进技术</h2>
    <button v-on:click="showInfo1">点我提示信息1(不传参)</button>
    <button @click="showInfo2(66)">点我提示信息2(传参)</button>
</div>

<script type="text/javascript">

    new Vue({
        el:'#root',
        data:{
            name:'牛客网'
        },
        methods:{
            showInfo1(event){
                console.log(event.target.innerText)
                alert('同学你好hhe!')
            },
            showInfo2(number){
                console.log(event.target.innerText)
                alert('同学' + number +'你好hah!')
            }
        }
    })
</script>

</body>
</html>

v-on:click="xxx"事件我们往往会简写成@click="xxx"形式

 3.3.2 事件修饰符

常用的事件修饰符 

1.prevent: 阻止默认事件(常用)
2.stop:阻止事件冒泡(常用)
3.once:事件只触发一次(常用)
4.capture: 使用事件的捕获模式
5.self:只有event.target是当前操作的元素是才触发事件
6.passive: 事件的默认行为立即执行,无需等待事件回调执行完毕

使用:(css可以根据自行水平更改 = =)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件修饰符</title>

    <style type="text/css">
        *{
        margin-top: 20px;
        }
        .demo1{
        height: 50px;
        background-color: #066aec;
        }
        .box1{
            padding: 5px;
            background-color: darkred;
        }
        .box2{
            padding: 5px;
            background-color: greenyellow;
        }
        .list{
            height: 200px;
            weight: 200px;
            background-color: saddlebrown;
            overflow: auto;
        }
        li{
            height: 100px;
        }
    </style>
</head>
<body>
<!--
        Vue中的事件修饰符
            1.prevent: 阻止默认事件(常用)
            2.stop:阻止事件冒泡(常用)
            3.once:事件只触发一次(常用)
            4.capture: 使用事件的捕获模式
            5.self:只有event.target是当前操作的元素是才触发事件
            6.passive: 事件的默认行为立即执行,无需等待事件回调执行完毕
            -->

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <h1>欢迎来到{{name}}学习</h1>
    <!-- 阻止默认事件 (常用)   -->
    <a href="http://www.baidu.com" @click.prevent="showInfo1">点我跳转</a>
    <!-- 阻止事件冒泡 (常用)   -->
    <div class='demo1' @click="showInfo1">
        <button @click.stop="showInfo1">点我提示信息</button>
    </div>
    <!-- 事件只触发一次 (常用) -->
    <div class="demo2">
        <button @click.once="showInfo1">点我提示信息</button>
    </div>
    <!-- 使用事件的捕获模式 -->
    <div class="box1" @click.capture="showMessage(1)">
        div1
        <div class="box2" @click="showMessage(2)">
            div2
        </div>
    </div>

    <!-- 只有event.target是当前操作的元素是才触发事件 -->
    <div class="demo1" @click.self="showInfo1">
        <button @click="showInfo1">点我提示信息</button>
    </div>

    <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕 -->
    <ul @wheel.passive="demo" class="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>


</div>
<script type="text/javascript">

   let vm = new Vue({
       el: "#root",
       data:{
           name: '牛客网'
       },
       methods: {
           showInfo1(e) {
               // e.preventDefault()
               // e.stopPropagation()
               alert('同学你好hhe!')
           },
           showMessage(msg) {
               alert(msg)
           },
           demo(){
               for (let i = 0; i = 1000; i++) {
                   console.log('@')
               }
           }
       }
   });

</script>

</body>
</html>

注意:

1. 当我们使用stop时,会阻止冒泡的发生,那什么是冒泡呢?经过测试,我们去除stop发现alert了两次,

说明我们既执行了button中的click也执行了外层div的click,说明是从内到外执行的

2.当我们使用capture时,会阻止捕获的发生,即当我们会先执行外层再执行内层,例如当我们点击div2时,我们会先输出1,再输出2。但当我们不适用capture时,默认为冒泡执行

3.3.3 键盘事件 

Vue中常用的按键别名
回车 => enter
删除 => delete(捕获”删除“和”退格“键)
退出 => esc
空格 => space
换行 => tab(特殊,必须配合keydown使用)
  上 => up
  下 => down
  左 => left
  右 => right

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>键盘事件</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <h1>欢迎来到{{name}}学习</h1>
    <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo1">

    <!--
        1.Vue中常用的按键别名
            回车 => enter
            删除 => delete(捕获”删除“和”退格“键)
            退出 => esc
            空格 => space
            换行 => tab(特殊,必须配合keydown使用)
              上 => up
              下 => down
              左 => left
              右 => right

        2.Vue未提供别名的按键,看一看使用按键原始的key值去绑定,但主要要转为kebab-case(短横线命名)

        3.系统修饰键(用法特殊): ctrl、alt、shift、meta
                (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
                (2).配合keydown使用:正常触发事件

        4.也可以使用keyCode去指定具体的按键(不推荐)

        5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
    -->

</div>

<script type="text/javascript">


    let vm = new Vue({
        el: "#root",
        data:{
            name: "heima"
        },
        methods:{
            showInfo1(e){
                // if(e.key == 'Enter') {
                //     console.log("您操作了键盘:" + e.target.value);
                // }
                console.log("您操作了键盘:" + e.target.value);
            }
        }
    })
</script>

</body>
</html>

注意:

1.Vue未提供别名的按键,看一看使用按键原始的key值去绑定,但主要要转为kebab-case(短横线命名)

2.系统修饰键(用法特殊): ctrl、alt、shift、meta
        (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
        (2).配合keydown使用:正常触发事件

3.也可以使用keyCode去指定具体的按键(不推荐)

4.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名

3.4 条件渲染

3.4.1 v-for

简单形式

v-for = " 元素名 in 数组名"

完整形式

v-for = "(元素名,key的值) in 数组名" :key="index"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表渲染</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <!-- 遍历数组 -->
    <h1>人员列表(遍历数组)</h1>
    <ul>
        <!--<li v-for="person in persons" :key="person.id">
            {{person.name}}-{{person.age}}
        </li>-->
        <li v-for="(person,index) in persons" :key="index">
            {{person.name}}-{{person.age}}
        </li>
    </ul>
    <!-- 遍历对象 -->
    <h1>汽车信息(遍历对象)</h1>
    <ul>
        <li v-for="(value,key) of car" :key="key">
            {{key}}--{{value}}
        </li>
    </ul>
    <!-- 测试遍历字符串 (用的少)-->
    <h1>测试遍历字符串</h1>
    <ul>
        <li v-for="(value,index) of str" :key="index">
            {{value}}--{{index}}
        </li>
    </ul>
    <!-- 测试遍历指定次数 (用的少)-->
    <h1>测试遍历指定次数</h1>
    <ul>
        <li v-for="(number,index) of 5" :key="index">
            {{number}}--{{index}}
        </li>
    </ul>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            persons:[
                {id:'001',name:'张三',age:'28'},
                {id:'002',name:'李四',age:'30'},
                {id:'003',name:'王五',age:'25'},
            ],
            car:{
                name:'迈巴赫',
                price:'300w',
                color:'black'
            },
            str:'hello'
        }
    })
</script>

</body>
</html>

当我们在每一个元素后面增加一个input框并且输入内容时使用数组下标作为key时,我们在数组头部添加一个元素,会发现原来input框对应的元素错乱了,因此在某些情况下,我们应该使用数组的唯一标识作为key

注意:

我们也可以使用计算属性,监视属性等改变数组的返回值遍历 

3.4.2 v-else 和 v-else-if

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>条件渲染</title>
</head>
<body>
<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    
    <!-- v-else和v-else-if -->
    <div v-if="n === 1">Angluar</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>我不需要条件哦~</div>

    <template v-if="n === 1">
        <h2>湖南</h2>
        <h2>北京</h2>
        <h2>广东</h2>
    </template>
</div>

<script type="text/javascript">
    const vm = new Vue({
        el: '#root',
        data:{
            name:'王者荣耀',
            n:1
        }
    })
</script>
</body>
</html>

 注意:当我们使用v-if时,即使第一条判断后,后面的v-if仍然会判断,但是使用v-else-if时,如果第一条判断语句为true时,else-if就不会执行了

3.4.3 v-show 

 v-show功能和v-if一样,但v-show性能略强于v-if

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>条件渲染</title>
</head>
<body>
<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <!-- 使用v-show做条件渲染 -->
<!--    <h2 v-show="false">欢迎来到{{name}}</h2>-->
<!--    <h2 v-show="1 === 1">欢迎来到{{name}}</h2>-->
    <h2 v-show="true">n的值为:{{n}}</h2>
    <button @click="n++">点我n值+1</button>

    <div v-show="n === 1">Angluar</div>

    <!-- 使用v-if做条件渲染 -->
<!--    <h2 v-if="true">欢迎来到{{name}}</h2>-->

</div>

<script type="text/javascript">
    const vm = new Vue({
        el: '#root',
        data:{
            name:'王者荣耀',
            n:1
        }
    })
</script>
</body>
</html>

3.4.4 v-text

 类似于插值语法,但不能识别html标签结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的内置指令</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>

 <!--

    v-test指令:
        1.作用: 向其所在的节点中渲染文本内容
        2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会
        -->

<div id="root">
    <div><h2>你好,{{name}}</h2></div>
    <div v-text="name"></div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            name: '黑麻',
        }
    })
</script>


</body>
</html>

3.4.5 v-html 

 类似于插值语法,但可以识别html标签结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的内置指令</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>

 <!--
    v-html指令:
        1.作用:向指定节点中渲染包含html结构的内容
        2.与插值语法的却别:
           (1).v-html会替换掉节点中所有的内容,{{xx}}则不会
           (2).v-html可以识别html结构
        3.严重注意: v-html有安全性问题
           (1).再网站上动态渲染任意html是非常危险的,容易导致XSS(跨站脚本攻击)攻击
           (2).一定要在可信的内容上使用v-html,不要用在用户提交的内容上
        -->

<div id="root">
    <div><h2>你好,{{name}}</h2></div>
    <div v-html="message"></div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            message: '<h1>你好啊!</h1>'
        }
    })
</script>


</body>
</html>

3.4.6 v-cloak 

解决网速慢时页面显示出{{xxx}}的问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的内置指令2</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    <style type="text/css">
    </style>
</head>
<body>

 <!--
    Vue常用指令:
        v-cloak指令(没有值):
            1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
            2.使用css配合v-cloak可以解决网速慢时页面显示出{{xxx}}的问题
        -->

<div id="root">
    <div v-cloak><h2>{{name}}</h2></div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            name: '黑麻',
        }
    })
</script>


</body>
</html>

 3.4.7 v-once

与事件中的.once不同,v-once是使所在节点仅在初次加载时渲染,后固定为静态内容 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的内置指令3</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    <style type="text/css">
    </style>
</head>
<body>

 <!--
    Vue常用指令:
        v-once指令(没有值):
            1.v-once所在的节点再初次动态渲染后,就视为静态内容了
            2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
        -->

<div id="root">
    <div>
        <h2 v-once>初始化的n值是: {{n}}</h2>
        <h2>当前的n值是: {{n}}</h2>
        <button @click="n++">点我n+1</button>
    </div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            n: 1,
        }
    })
</script>


</body>
</html>

3.4.8 v-pre 

 没有使用指令语法,没有使用插值语法的节点,会加快编译

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的内置指令3</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    <style type="text/css">
    </style>
</head>
<body>

 <!--
    Vue常用指令:
        v-pre指令(没有值):
            1.跳过其所在节点的编译过程
            2.可利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
        -->

<div id="root">
    <div>
        <h2 v-pre>Vue其实很简单</h2>
        <h2>当前的n值是: {{n}}</h2>
        <button @click="n++">点我n+1</button>
    </div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            n: 1,
        }
    })
</script>


</body>
</html>

3.4.9 自定义指令 

 函数式:

使用directives定义自定义指令,function xxx(){}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的自定义指令(函数式)</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    <style type="text/css">
    </style>
</head>
<body>

 <!--
    自定义指令:

        -->

<div id="root">
    <div>
        <h2>{{name}}</h2>
        <h2>当前的n值是: <span v-text="n"></span></h2>
        <h2>放大10倍的n值是: <span v-big="n"></span></h2>
        <button @click="n++">点我n+1</button>
    </div>
</div>

<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            n: 1,
            name:'黑麻'
        },
        directives:{
            //big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
            big(element,binding){
                console.log('@@')
                element.innerText = binding.value * 10
            }
        }
    })
</script>


</body>
</html>

 对象式:

使用directives定义自定义指令,xxx: { 方法(){} }

使用对象式自定义指令时,配置对象中常用的3个问题

(1).bind:指令与元素成功绑定时回调

(2).inserted:指令所在元素被插入页面时调用

(3).update:指令所在模板结构被重新解析时调用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue的自定义指令(对象式)</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    <style type="text/css">
    </style>
</head>
<body>

 <!--
    自定义指令:
           语法:
                (1).局部指令:
                    new Vue({                             new Vue({
                        directives:{指令名:配置对象}  或            directives{指令名:回调函数}
                                 })                                            })
                (2).全局指令:
                    Vue.directive(指令名:配置对象)   或   Vue.directive(指令名:回调函数)
            二、配置对象中常用的3个问题
                (1).bind:指令与元素成功绑定时回调
                (2).inserted:指令所在元素被插入页面时调用
                (3).update:指令所在模板结构被重新解析时调用
            三、备注
               1.指令定义时不加v-,但使用时要加v-
               2.指令名如果是多个单词,要使用kebab-case命名方式,不要用驼峰命名
        -->

<div id="root">
    <div>
        <h2>{{name}}</h2>
        <h2>当前的n值是: <span v-text="n"></span></h2>
        <h2>放大10倍的n值是: <span v-big="n"></span></h2>
        <button @click="n++">点我n+1</button>
    <hr/>
        <input type="text" v-fbind:value="n">
        <input type="text" v-big-number:value="n">
    </div>
</div>

<script type="text/javascript">

    //配置全局指令
    /*Vue.directive('big',function (element,binding){
        console.log('big',this)//此处的this是window
        // console.log('@@')
        element.innerText = binding.value * 10
    })*/

    const vm = new Vue({
        el: '#root',
        data:{
            n: 1,
            name:'黑麻'
        },
        directives:{
            //big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
            big(element,binding){
                console.log('big',this)//此处的this是window
                // console.log('@@')
                element.innerText = binding.value * 10
            },
            fbind:{
                bind(element,binding){
                    //指令与元素成功绑定时(一上来)
                    console.log('bind被调用')
                    element.value = binding.value
                },
                inserted(element,binding){
                    //指令所在元素被插入页面时
                    console.log('inserted被调用')
                    element.focus();
                },
                update(element,binding){
                    //指令所在的模板被重新解析时
                    console.log('update被调用')
                    element.value = binding.value
                }
            },
            'big-number':{

            }
        }
    })
</script>


</body>
</html>

 注意:

1.指令定义时不加v-,但使用时要加v-

2.指令名如果是多个单词,要使用kebab-case命名方式,不要用驼峰命名

4. 表单双向绑定

4.1  什么是双向数据绑定

Vue.js是一个MV VM框架, 即数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vue x那么数据流也是单项的,这时就会和双向数据绑定有冲突。

(1)为什么要实现数据的双向绑定

Vue.js中,如果使用vuex, 实际上数据还是单向的, 之所以说是数据双向绑定,这是用的UI控件来说, 对于我们处理表单, Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。

4.2  在表单中使用双向数据绑定

你可以用v-model指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇, 但v-model本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model会忽略所有表单元素的valuecheckedselected特性的初始值而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值!

1.单行文本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<div id="app">
    <!-- 单行文本 -->
    <input type="text" v-model="message"/>{{message}}

    <span>{{selected}}</span>
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        data:{
           message: "狂神说java"

        }
    });
</script>

</body>
</html>

2.多行文本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<div id="app">

    <!-- 多行文本 -->
    <textarea v-model="message"></textarea>
    {{message}}
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message: "狂神说java"
        }
    });
</script>

</body>
</html>

3.单选按钮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<div id="app">

    <!-- 单选框 -->
    <input type="radio" name="sex" value="男" v-model="gender"> 男
    <input type="radio" name="sex" value="女" v-model="gender"> 女
    <p>
        选中了谁: {{gender}}
    </p>

  
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        data:{
           gender: ''
        }
    });
</script>

</body>
</html>

4.下拉框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<div id="app">
   
    <!-- 下拉框 -->
    下拉框:
    <select v-model="selected">
        <option value="" disabled>--请选择--</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>

    <span>{{selected}}</span>
</div>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<script>
    var vm = new Vue({
        el: "#app",
        data:{
            selected: ''
        }
    });
</script>

</body>
</html>

5.单复选框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    单复选框:
    <input type="checkbox" id="checkbox" v-model="checked">
    &nbsp;&nbsp;
    <label for="checkbox">{{checked}}</label>
</div>

<script src="../js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            checked:false
        }
    });
</script>
</body>
</html>

6.多复选框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    多复选框:
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
    &nbsp;&nbsp;
    <label for="jack">Jack</label>
    <input type="checkbox" id="join" value="Join" v-model="checkedNames">
    &nbsp;&nbsp;
    <label for="join">Jack</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
    &nbsp;&nbsp;
    <label for="mike">Mike</label>
    <span>选中的值:{{checkedNames}}</span>
</div>

<script src="../js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            checkedNames:[]
        }
    });
</script>
</body>
</html>

5. 计算属性

计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!

5.1.原理:

底层借助了Object.defineProperty方法提供的getter和setter

5.2.执行时机

(1).初次读取fullName时 (2).所依赖的数据发生变化时

5.3.优势:

与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

首先我们以method方法实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例-methods实现</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

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


<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        methods:{
            fullName(){
                return this.firstName + "-" + this.lastName;
            }
        }
    });
</script>

</body>
</html>

接下来以计算属性实现 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例-计算属性实现</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

        <div id="root">
            姓:<input type="text" v-model:value="firstName"> <br/><br/>
            名:<input type="text" v-model="lastName"> <br/><br/>
            全名: <span>{{fullName}}</span>
        </div>

        <!--
            计算属性:
                1.定义:要用的属性不存在,要通过已有属性计算得来
                2.原理:底层借助了Object.defineProperty方法提供的getter和setter
                3.get函数什么时候执行:
                    (1).初次读取fullName时
                    (2).所依赖的数据发生变化时
                4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
                5.备注:
                    (1).计算属性最终会出现在vm上,直接读取使用即可
                    (2).如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化
            -->


<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
            fullName:{
                //get当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                //get什么时候调用?1.初次读取fullName时,2.所依赖的数据发生变化时
                get(){
                    console.log('get被调用了..')
                    return this.firstName + "-" + this.lastName
                },
                //set什么时候调用? fullName的值被修改时
                set(value){
                    console.log('set被调用了',value);
                    const arr = value.split("-");
                    this.firstName = arr[0]
                    this.lastName = arr[1]
                }
            }
        }
    });
</script>

</body>
</html>

注意:methods和computed里的东西不能重名

(1).计算属性最终会出现在vm上,直接读取使用即可

(2).如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化

说明:

  • methods:定义方法, 调用方法使用fullName(), 需要带括号

  • computed:定义计算属性, 调用属性使用fullName, 不需要带括号

  • 如何在方法中的值发生了变化,则缓存就会刷新!

    结论:
      调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;

另:

 计算属性可以采用简写形式,但仅当我们只读取时使用

computed:{
        //简写,只考虑读取,不考虑修改时才可使用简写形式
        fullName:function(){
            console.log('get被调用了..')
            return this.firstName + "-" + this.lastName
        }

完整形式:

//完整写法
fullName:{
    get(){
        console.log('get被调用了..')
        return this.firstName + "-" + this.lastName
    },
    set(value){
        console.log('set被调用了',value);
        const arr = value.split("-");
        this.firstName = arr[0]
        this.lastName = arr[1]
    }
}

6. Watch监视 

当我们需要在数据发生改变时,执行一些操作的时候,我们可以使用watch监视进行操作

6.1 普通监视 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例_监视属性</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click="changeWeather">切换天气</button>
</div>

    <!--
        监视属性watch
            1.当被监视的属性变化时,回调函数自动调用,进行相关操作
            2.监视的属性必须存在才能进行监视!
            3.监视的两种写法:
                (1). new Vue时传入watch配置
                (2). 通过vm.$watch监视
        -->

<script type="text/javascript">
    const vm = new Vue({
        el: '#root',
        data:{
            isHot:true
        },
        computed:{
            info(){
                return this.isHot?'炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot;
            }
        },
        watch:{
            isHot:{
                immediate:true, //初始化时调用handler一次
                //handler当isHot发生改变时调用
                handler(newValue,oldValue){
                    console.log('isHot被修改了!' + '原始值:' + oldValue + ",新值:" + newValue);
                }
            }
        }
    })

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

说明:1.我们定义了方法,当我们点击事件时,会对isHot进行更改,我们在watch中定义了监视

2.当我们更改了isHot时,会执行watch里的handler方法 

6.2 配置监视的属性 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例_监视属性02</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click="changeWeather">切换天气</button>

    <h2>a的值{{number.a}}</h2>
    <button @click="number.a++">点我a的值+1</button>
    <h2>a的值{{number.b}}</h2>
    <button @click="number.b++">点我b的值+1</button>
</div>

    <!--
        深度监视
            (1).Vue中的watch默认不监测的对象内部值的变化(一层)
            (2).配置deep:true可以监测对象内部值的改变(多层)
        备注:
            (1).Vue自身可以检测对象内部值的改变,但Vue提供给的watch默认不可以!
            (2).使用Watch时根据数据的具体结构,决定是否采用深度监视
        -->

<script type="text/javascript">
    const vm = new Vue({
        el: '#root',
        data:{
            isHot:true,
            number:{
                a:1,
                b:1
            }
        },
        computed:{
            info(){
                return this.isHot?'炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot;
            }
        },
        watch:{
            isHot:{
                immediate:true, //初始化时调用handler一次
                //handler当isHot发生改变时调用
                handler(newValue,oldValue){
                    console.log('isHot被修改了!' + '原始值:' + oldValue + ",新值:" + newValue);
                }
            },
            //监视多级结构中某个属性的变化
            /*'number.a':{
                immediate:true, //初始化时调用handler一次
                //handler当isHot发生改变时调用
                handler(){
                    console.log('a被改变了');
                }
            }*/
            number: {
                //监视多级结构中所有属性的变化, 深度监视
                deep:true,
                handler(){
                    console.log('number的值被修改了!');
                }
            }
        }
    })

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

说明:1.当我们需要在初始化数据时就默认执行一次watch,我们需要配置一个immediate:true

2.当我们监视一个对象时,当对象内部的数据更改时我们的普通监测监测不到数据的变化,这时我们需要使用深度监视,,也就是在对应数据配置中配置deep:true开启深度监视 

6.3 简写形式 

//简写
vm.$watch('isHot',function (newValue,oldValue){
    console.log('isHot修改了',newValue,oldValue)
})

6.4  Watch 与 computed 

computer和watch之间的区别:

1.computer能完成的功能,watch都可以完成

2.watch能完成的功能,computer不一定可以完成,例如: watch可以进行异步操作

两个重要的小原则:

1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或 组件实例对象

2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数,Promise的回调函数等),最好写成箭头函数, 这样this的指向才是vm 或 组件实例对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例-watch监视实现</title>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

        <div id="root">
            姓:<input type="text" v-model:value="firstName"> <br/><br/>
            名:<input type="text" v-model="lastName"> <br/><br/>
            全名: <span>{{fullName}}</span>
        </div>

    <!--
        computer和watch之间的区别:
            1.computer能完成的功能,watch都可以完成
            2.watch能完成的功能,computer不一定可以完成,例如: watch可以进行异步操作
        两个重要的小原则:
            1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或 组件实例对象
            2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数,Promise的回调函数等),最好写成箭头函数,
               这样this的指向才是vm 或 组件实例对象
        -->
<script type="text/javascript">

    const vm = new Vue({
        el: '#root',
        data:{
            firstName:'张',
            lastName:'三',
            fullName:'张-三'
        },
        computed:{
        },
        watch:{
            firstName(newValue){
                this.fullName = newValue + '-' +this.lastName;
            },
            lastName(newValue){
                this.fullName = this.firstName + '-' + newValue;
            }
        }
    });
</script>

</body>
</html>

6.5 数据监测总结

Vue监测数据的原理: 

  1.vue会监测data中所有层次的数据

  2.如何监测对象中的数据: 通过setter实现监测,且要在new Vue时就传入要监测的数据.

(1).对象中后追加的属性,Vue默认不做响应式处理

(2).如需给后添加的属性做响应式,请使用如下api: Vue.set(target.propertyName/index.value)或 vm.$set(target.propertyName/index.value)

3.如何监测数组中的数据: 通过包裹数组更新元素的方法实现,本质就是做了两件事:

(1).调用原生对应的方法对数组进行更新

(2).重新解析模板,进而更新页面

4.在Vue修改数组中的某个元素一定要用如下方法:

1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

2.Vue.set()或 vm.$set() 特别注意:Vue.set() 和 vm.$set() 不能给vm或vm的根数据对象添加属性!!!

 7. 绑定样式

7.1 class样式 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绑定样式</title>

    <style type="text/css">
        .basic{
            width: 400px;
            height: 100px;
            border: 1px solid lightslategrey;
        }
        .happy{
            width: 300px;
            height: 80px;
            border: 1px solid red;
            font-size: 50px;
            background-color: cornflowerblue;
        }
        .sad{
            width: 300px;
            height: 80px;
            border: 1px solid black;
            background-color: greenyellow;
        }
        .normal{
            width: 300px;
            height: 80px;
            border: 1px solid red;
            background-color: #303133;
        }
        .atguigu1{
            width: 500px;
            height: 120px;
            border: 2px blue;
            background-color: purple;
        }
        .atguigu2{
            width: 500px;
            height: 120px;
            border: 2px yellow;
            background-color: deeppink;
        }
        .atguigu3{
            width: 500px;
            height: 120px;
            border: 2px darkred;
            background-color: orange;
        }
    </style>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <!-- 绑定class样式 -- 字符串写法,适用于:样式的类名不确定,需要动态指定 -->
    <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
    <!-- 绑定class样式 -- 数组写法,适用于:要绑定的样式个数不确定,名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div>
    <!-- 绑定class样式 -- 对象写法,适用于:要绑定的样式个数确定,名字也确定,但要动态决定用不用 -->
    <div class="basic" :class="classObj">{{name}}</div>
</div>

        <!--
            绑定样式
                1:class样式
                    写法: :class='xxx' xxx可以是字符串、数组、对象
                    字符串写法适用于:类名不确定,要动态获取
                    对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
                    数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定是否使用
              
                    -->

<script type="text/javascript">

    const vm = new Vue({
        el:'#root',
        data:{
            name:"黑麻",
            mood:'normal',
            classArr:['atguigu1','atguigu2','atguigu3'],
            classObj:{
                atguigu1:false,
                atguigu2:false
            }
        },
        methods:{
            changeMood(){
                const arr = ['happy','sad','normal']
                var i = Math.floor(Math.random() * 3);
                 this.mood = arr[i];
                // this.mood = 'happy'
            }
        }
    })
</script>

</body>
</html>

 7.2 style样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绑定样式</title>

    <style type="text/css">
        
    </style>
</head>
<body>

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
  
    <div class="basic" :style="styleObj">{{name}}</div>
</div>

        <!--
            绑定样式
               
                2:style样式
                    :style="{fontSize:xxx}"其中xxx是动态的
                    :style="[a,b]"其中a、b是样式对象
                    -->

<script type="text/javascript">

    const vm = new Vue({
        el:'#root',
        data:{
            styleObj:{
                fontSize: '50px',
                color: 'red'
            }
        }
    })
</script>

</body>
</html>

8. 过滤器 

 对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>过滤器</title>
</head>
<body>
<!--
    过滤器:
       定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
       语法:
            1.注册过滤器:Vue.filter(name,callback)或new Vue(filters:{})
            2.使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
       备注:
            1.过滤器也可以接受额外参数,多个过滤器也可以串联
            2.并没有改变原本的数据,是产生新的对应的数据 
-->

<!-- 导入 vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

<div id="root">
    <!-- 过滤器 -->
    <h2>使用过滤器: {{time | timeFormater}}</h2>
</div>

<script type="text/javascript">

    //配置全局过滤器
    Vue.filter('timeFormater',function (value){
        console.log('执行了过滤器方法...')
        return 'hello'
    })

    const vm = new Vue({
        el:'#root',
        data:{
            time:123456789
        },
        filters:{
            //配置局部过滤器
            helloFilter(){
                console.log('执行了filter过滤器方法...')
                return 'hello'
            }
        }
    })
</script>

</body>
</html>

 语法:

1.注册过滤器:Vue.filter(name,callback)或new Vue(filters:{})

2.使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"

注意: 

1.过滤器也可以接受额外参数,多个过滤器也可以串联

2.并没有改变原本的数据,是产生新的对应的数据

9. Vue的生命周期

1又名:生命周期回调函数,生命周期函数,生命周期钩子

9.1 定义:

Vue在关键时刻帮我们调用的一些特殊名称的函数

生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的

生命周期函数的this指向是vm 或 组件实例对象

9.2 解析生命周期 

beforeCreate():还未能访问到data数据,method方法,页面还是未传值

 created() :能访问到data数据,method方法

 beforeMount()未经解析的DOM结构,所有对DOM的操作都无效

 mounted():经过编译的DOM,所有对DOM的操作都有效(但尽量避免直接操作DOM)

 beforeUpdate():数据是新的,但页面是旧的

 updated():此时数据是新的,页面也是新的

 beforeDestroy():vm中data.methods等都处于可用状态,但马上要执行销毁程序

destroyed():程序销毁 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue的生命周期2</title>

    <!-- 导入 vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>

<!--
    生命周期:

        -->

<div id="root">
    <h2>当前n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
    <button @click="destroyFox">执行销毁程序</button>
<!--    <h2 :style="{opacity: opacity}">欢迎学习</h2>-->
</div>

<script type="text/javascript">
   const vm = new Vue({
        el:'#root',
       // template:`
       //     <div>
       //     <h2>当前n值是:{{n}}</h2>
       //     <button @click="add">点我n+1</button>
       //     </div>`,
        data:{
            n:0,
            // opacity:1
        },
       methods:{
            add(){
                console.log('add被调用')
                this.n ++
            },
           destroyFox(){
                console.log('我快要上西天了')
                this.$destroy();
           }
       },
       beforeCreate(){
            //还未能访问到data数据,method方法
            console.log('beforeCreate')
           // console.log(this)
           // debugger;
       },
       created(){
            //能访问到data数据,method方法
           console.log('create')
           // console.log(this)
           // debugger;
       },
        beforeMount(){
            //未经解析的DOM结构,所有对DOM的操作都无效,  例如控制台:  document.querySelector('h2').innerText = '哈哈哈'
           console.log('beforeMount')
           //  console.log(this)
           // debugger;
       },
       mounted(){
            //经过编译的DOM,所有对DOM的操作都有效(但尽量避免)
           console.log('mounted')
           // console.log(this)
           // debugger;
       },
       beforeUpdate(){
            //数据是新的,但页面是旧的
           console.log('beforeUpdate')
           // console.log(this)
           // debugger;
       },
       updated(){
            //此时数据是新的,页面也是新的
           console.log('updated')
           // console.log(this)
           // debugger;
       },
       beforeDestroy(){
            //vm中data.methods等都处于可用状态,但马上要执行销毁程序
           console.log('beforeDestroy')
            this.add()
           // console.log(this)
           // debugger;
       },
       destroyed(){
            console.log('destroyed')
           console.log(this)

       }
    })

</script>

</body>
</html>

11. Vue实战 

使用ElementUI组件库,进行vue实战 

11.1 创建工程

注意:命令行都要使用管理员模式运行
1、创建一个名为hello-vue的工程vue init webpack hello-vue
2、安装依赖, 我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件

#进入工程目录
cd hello-vue
#安装vue-routern 
npm install vue-router --save-dev
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
#启功测试
npm run dev

3、Npm命令解释:

  • npm install moduleName:安装模块到项目目录下
  • npm install -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm config prefix的位置
  • npm install -save moduleName:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写
  • npm install -save-dev moduleName:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写

11.2 创建登录页面

把没有用的初始化东西删掉!
  在源码目录中创建如下结构:

  • assets:用于存放资源文件
  • components:用于存放Vue功能组件
  • views:用于存放Vue视图组件
  • router:用于存放vue-router配置

创建首页视图,在views目录下创建一个名为Main.vue的视图组件:

<template>
	<div>首页</div>
</template>
<script>
	export default {
			name:"Main"
	}
</script>
<style scoped>
</style>

创建登录页视图在views目录下创建名为Login.vue的视图组件,其中el-*的元素为ElementUI组件;

<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item label="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>

    <el-dialog title="温馨提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
          <el-button type="primary" @click="dialogVisible = false">确定</el-button>
        </span>
    </el-dialog>
  </div>
</template>

<script>
    export default {
        name: "Login",
      data(){
          return{
            form:{
              username:'',
              password:''
            },
            //表单验证,需要在 el-form-item 元素中增加prop属性
            rules:{
              username:[
                {required:true,message:"账号不可为空",trigger:"blur"}
              ],
              password:[
                {required:true,message:"密码不可为空",tigger:"blur"}
              ]
            },

            //对话框显示和隐藏
            dialogVisible:false
          }
      },
      methods:{
          onSubmit(formName){
            //为表单绑定验证功能
            this.$refs[formName].validate((valid)=>{
              if(valid){
                //使用vue-router路由到指定界面,该方式称为编程式导航
                this.$router.push('/main');
              }else{
                this.dialogVisible=true;
                return false;
              }
            });
          }
      }
    }
</script>

<style lang="scss" scoped>
  .login-box{
    border:1px solid #DCDFE6;
    width: 350px;
    margin:180px auto;
    padding: 35px 35px 15px 35px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    box-shadow: 0 0 25px #909399;
  }
  .login-title{
    text-align:center;
    margin: 0 auto 40px auto;
    color: #303133;
  }
</style>

创建路由,在router目录下创建一个名为index.js的vue-router路由配置文件

//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
  routes: [
    {
      //登录页
      path: '/main',
      component: Main
    },
    //首页
    {
      path: '/login',
      component: Login
    },
  ]

})

APP.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>


export default {
  name: 'App',

}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from "./router"

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(router)
Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  render:h=>h(App)
})

测试:在浏览器打开 http://localhost:8080/#/login
如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,则需要更换版本去package.json文件里面的 "sass-loader"的版本进行更改,然后重新cnpm install就可以了;

11.3 路由嵌套

嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
demo
1、 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
Profile.vue

<template>
  <h1>个人信息</h1>
</template>
<script>
  export default {
    name: "UserProfile"
  }
</script>
<style scoped>
</style>

2、在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
List.vue

<template>
  <h1>用户列表</h1>
</template>
<script>
  export default {
    name: "UserList"
  }
</script>
<style scoped>
</style>

3、 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
Main.vue

<template>
    <div>
      <el-container>
        <el-aside width="200px">
          <el-menu :default-openeds="['1']">
            <el-submenu index="1">
              <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
              <el-menu-item-group>
                <el-menu-item index="1-1">
                <!--插入的地方-->
                  <router-link to="/user/profile">个人信息</router-link>
                </el-menu-item>
                <el-menu-item index="1-2">
                <!--插入的地方-->
                  <router-link to="/user/list">用户列表</router-link>
                </el-menu-item>
              </el-menu-item-group>
            </el-submenu>
            <el-submenu index="2">
              <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
              <el-menu-item-group>
                <el-menu-item index="2-1">分类管理</el-menu-item>
                <el-menu-item index="2-2">内容列表</el-menu-item>
              </el-menu-item-group>
            </el-submenu>
          </el-menu>
        </el-aside>

        <el-container>
          <el-header style="text-align: right; font-size: 12px">
            <el-dropdown>
              <i class="el-icon-setting" style="margin-right: 15px"></i>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item>个人信息</el-dropdown-item>
                <el-dropdown-item>退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </el-header>
          <el-main>
          <!--在这里展示视图-->
            <router-view />
          </el-main>
        </el-container>
      </el-container>
    </div>
</template>
<script>
    export default {
        name: "Main"
    }
</script>
<style scoped lang="scss">
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  .el-aside {
    color: #333;
  }
</style>

4、 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
index.js

//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//导入子模块
import UserList from "../views/user/List";
import UserProfile from "../views/user/Profile";

//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
  routes: [
    {
      //登录页
      path: '/main',
      component: Main,
      //  写入子模块
      children: [
        {
          path: '/user/profile',
          component: UserProfile,
        }, {
          path: '/user/list',
          component: UserList,
        },
      ]
    },
    //首页
    {
      path: '/login',
      component: Login

    },
  ]
})

11.4 参数传递

用的还是上述例子的代码 修改一些代码 这里不放重复的代码了
第一种取值方式
1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符

{
	path: '/user/profile/:id', 
	name:'UserProfile', 
	component: UserProfile
}

2、传递参数
 此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;

<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
12

3、在要展示的组件Profile.vue中接收参数 使用 {{$route.params.id}}来接收
Profile.vue 部分代码

<template>
  <!--  所有的元素必须在根节点下-->
  <div>
    <h1>个人信息</h1>
    {{$route.params.id}}
  </div>
</template>

第二种取值方式 使用props 减少耦合
1、修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性

{
	path: '/user/profile/:id', 
	name:'UserProfile', 
	component: UserProfile, 
	props: true
}

2、传递参数和之前一样 在Main.vue中修改route-link地址

<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>

3、在Profile.vue接收参数为目标组件增加 props 属性
Profile.vue

<template>
  <div>
    个人信息
    {{ id }}
  </div>
</template>
<script>
    export default {
      props: ['id'],
      name: "UserProfile"
    }
</script>
<style scoped>
</style>

11.5 组件重定向

重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如:
在router下面index.js的配置

{
  path: '/main',
  name: 'Main',
  component: Main
},
{
  path: '/goHome',
  redirect: '/main'
}

说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件;

使用的话,只需要在Main.vue设置对应路径即可;

<el-menu-item index="1-3">
    <router-link to="/goHome">回到首页</router-link>
</el-menu-item>

11.6 路由模式与 404

路由模式有两种

修改路由配置,代码如下:

export default new Router({
  mode: 'history',
  routes: [
  ]
});

404 demo
1.创建一个NotFound.vue视图组件
NotFound.vue

<template>
    <div>
      <h1>404,你的页面走丢了</h1>
    </div>
</template>
<script>
    export default {
        name: "NotFound"
    }
</script>
<style scoped>
</style>

2.修改路由配置index.js

import NotFound from '../views/NotFound'
{
   path: '*',
   component: NotFound
}

11.7 路由钩子与异步请求

beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行

在Profile.vue中写

  export default {
    name: "UserProfile",
    beforeRouteEnter: (to, from, next) => {
      console.log("准备进入个人信息页");
      next();
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("准备离开个人信息页");
      next();
    }
  }

参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

11.8 在钩子函数中使用异步请求

1、安装 Axios

cnpm install --save vue-axios

2、main.js引用 Axios

import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)

3、准备数据 : 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里

// 静态数据存放的位置
static/mock/data.json

4.在 beforeRouteEnter 中进行异步请求
Profile.vue

  export default {
    //第二种取值方式
    // props:['id'],
    name: "UserProfile",
    //钩子函数 过滤器
    beforeRouteEnter: (to, from, next) => {
      //加载数据
      console.log("进入路由之前")
      next(vm => {
        //进入路由之前执行getData方法
        vm.getData()
      });
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("离开路由之前")
      next();
    },
    //axios
    methods: {
      getData: function () {
        this.axios({
          method: 'get',
          url: 'http://localhost:8080/static/mock/data.json'
        }).then(function (response) {
          console.log(response)
        })
      }
    }
  }

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值