vue框架

vue概述

1.vue基础

是一个js框架
可以简化dom操作
响应式数据驱动

1.第一个vue程序

步骤
①导入vue.js
②创建vue实例对象,设置el属性和data属性
③实用简洁的模板语法把数据渲染到页面上

<body>
    <div id='app'>
        {{message}}
    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '你好 luoluo'
            }
        })
    script>
body>

2.el挂载点

el是设置vue实例挂载的元素
vue框架_第1张图片
补充:如果el挂载点命中了多个双标签,则只会在第一个双标签生效

3.data 数据对象

vue中用到的数据定义在data中,data中可以写复杂类型的数据,只要在渲染复杂数据时遵守js语法即可

<body>
    <div id='app'>
        {{message}} <br>
        <span>你的家乡在{{home.land}},所属岛天为{{home.daotian}}span>
        <div>技能有{{jineng[0]}},{{jineng[1]}},{{jineng[2]}}div>
    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '你好 luoluo',
                home: {
                    land: '灵帝国',
                    daotian: 'six'
                },
                jineng: ['万伥驾驭', '生死玄域', '天命之瞳']
            }
        })
    script>
body>

在这里插入图片描述

2.本地应用

主要学习使用vue指令
大致可分为
内容绑定,事件绑定
显示切换,属性绑定
列表循环,表单元素绑定

1.v-text

设置文本内容,全部修改,会顶替掉原来的内容
{{}}方法是局部修改

<body>
    <div id='app'>
        <div>{{message}}灵帝国div>
        <div v-text='message'>灵帝国div>
        <div v-text='info'>灵帝国div>
        <div v-text='info+"补充"'>灵帝国div>

    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '你好 luoluo',
                info: '六重岛天'
            }

        })
    script>
body>

vue框架_第2张图片

2.v-html

和v-text基本一样,但是v-html能够解析html元素

<body>

    <div id='app'>
        <div v-text='message'>灵帝国div>
        <div v-html='message'>灵帝国div>

    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '原神'
            }

        })
    script>
body>

在这里插入图片描述
补充
cookie简述
vue框架_第3张图片
cookie可以在f12的application的cookies中找到
可以用cookie editer插件批量处理cookie
刷新cookie是不会丢失的,存于硬盘中
document.cookie获取当前页面的cookie
当data中保存的数据为如下类型时,用v-html渲染,在跳转的时候就会带着本页面的cookie一起走,如果页面的渲染方式为v-html,评论区发送了该数据,且跳转目标位非法者的服务器,就会导致其他点击此链接的用户泄露cookie信息

htm2: 'come here'

所以
v-html有个非常严重的安全性问题,不要随意在网站上动态渲染html内容,要在可信内容上用v-html,不要再用户提交的内容上用

3.v-on

<body>

    <div id='app'>
        <input type="button" value="v-on指令" v-on:click="dot1">
        <input type="button" value="v-on指令简写" @click="dot1">
        <input type="button" value="双击事件" @dblclick="dot2">
        <h2 v-text="message" @click="change">h2>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '霸天虎'
            },
            methods: {
                dot1: function () {
                    console.log('五重岛田');
                },
                dot2: function () {
                    console.log('六重岛田');
                },
                change: function () {
                    this.message = '镇狱兽'
                }
            }
        })
    script>
body>

注意:
①v-on用于绑定事件
②简写方法使用@代替
③在方法中使用this可以修改data数据元素

补充
①事件绑定的方法写成函数调用的方式,可以传入自定义参数
②事件后面可以跟上 .修饰符对事件进行限制
③比如@keyup.enter,只有按下回车键时才会触发

<body>

    <div id='app'>
        <input type="text" @keyup.enter="dot(666)">
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '霸天虎'
            },
            methods: {
                dot: function (p1) {
                    alert(p1)
                },

            }
        })
    script>
body>

在这里插入图片描述

案例
计数器

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        #app {
            display: flex;
            width: 300px;
            height: 48px;
            font-size: 20px;
            border: 0px;
        }

        #app span {
            flex: 1;
            text-align: center;
            line-height: 48px;
            border: 1px solid #999;
        }

        #app button {
            width: 100px;
        }
    style>
head>

<body>
    <div id="app">
        <button @click='sub'>-button>
        <span v-text="num">span>
        <button @click='add'>+button>
    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                num: 1
            },
            methods: {
                add: function () {
                    this.num++
                },
                sub: function () {
                    this.num--
                }
            }

        })
    script>
body>

html>

在这里插入图片描述

4.v-show

<body>
    <div id='app'>
        <input type="button" value="切换显示" @click="ischange">
        <img v-show="isShow" src="https://tse3-mm.cn.bing.net/th/id/OIP-C.H1T_sC5zrcopALAu-hAFOQHaHP?pid=ImgDet&rs=1"
            alt="">
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                age: 16,
                isShow: false
            },
            methods: {
                ischange: function () {
                    this.isShow = !this.isShow
                }
            }

        })
    script>
body>

vue框架_第4张图片
总结
①v-show指令用于根据真假切换元素现实状态
②原理是修改元素的display,实现显示隐藏
③指令后面的内容,最终都会解析为布尔值
④true显示元素,false隐藏元素
⑤数据改变之后,对应元素的显示状态也会同步更新

5.v-if

①和v-show作用类似,都是根据真假显示隐藏元素
②不同的是,v-show是是操纵样式控制显示和隐藏,而v-if是直接操纵dom元素
③为true,元素存在于dom树,为false,从dom树中移除
④频繁切换用v-show,反之v-if
⑤还有v-else-if,只有在前面的v-if不成立才进行判断,当然还有v-else,这些个是一组
⑥v-if可以和templete搭配,v-show不可以,templete不影响页面结构,即不占用dom空间,当同时要控制两个及以上的div时,放在一个tempplate中进行统一控制

<template v-if='n===1'>
    <h2>1h2>
    <h2>2h2>
    <h2>3h2>
template>
<body>
    <div id='app'>
        <input type="button" value="切换显示" @click="ischange">
        <img v-if="isShow" src="https://tse3-mm.cn.bing.net/th/id/OIP-C.H1T_sC5zrcopALAu-hAFOQHaHP?pid=ImgDet&rs=1"
            alt="">
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                isShow: false
            },
            methods: {
                ischange: function () {
                    this.isShow = !this.isShow
                }
            }

        })
    script>
body>

6.v-bind

①v-bind用于为元素绑定属性(src,class等)
②完整写法是v-bind:属性名,简写可以省略v-bind
③需要动态增删class可以用对象的方式,下面对象里冒号后面的truefalse决定了class值的有无

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        .active {
            border: 1px solid red;
        }
    style>
head>

<body>
    <div id="app">
        <img v-bind:src="imgSrc" alt="">
        <img :src="imgSrc" alt="" :class="{active:isActive}" @click="change">

    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                imgSrc: 'https://www.eayyou.com/upload/resources/image/2020/09/29/327507_600x600.jpg',
                isActive: false

            },
            methods: {
                change: function () {
                    this.isActive = !this.isActive
                }
            }
        })
    script>
body>

html>

案例-图片切换

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片切换title>
    <style>
        a {
            text-decoration: none;
            width: 25px;
            height: 40px;
            background-color: rgba(0, 0, 0, 0.5);
            color: #fff;
            font-size: 18px;
            line-height: 40px;
            text-align: center;
        }

        .box {
            position: relative;
            width: 300px;
            height: 240px;
            /* background-color: pink; */
            margin: 160px auto;
            border: 1px solid #ccc;
        }

        .imgg {
            width: 100%;
            height: 100%;
        }

        .prev {
            position: absolute;
            left: 0;
            top: 100px;


        }

        .next {
            position: absolute;
            right: 0;
            top: 100px;

        }
    style>
head>

<body>
    <div id="app">
        <div class="box">
            <img :src="imgSrc[index]" alt="" class="imgg">
            <a href="javascript:;" class="prev" @click="prev" v-show="index!=0"><a>
            <a href="javascript:;" class="next" @click="next" v-show="index">>a>
        div>
    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                imgSrc: ['https://www.eayyou.com/upload/resources/image/2020/09/29/327507_600x600.jpg',
                    'https://imgo.hackhome.com/img2020/10/13/14/304373101.png',
                    'https://tse2-mm.cn.bing.net/th/id/OIP-C.9sMVPeuAGT4uF_G2qTjrBAHaEy?pid=ImgDet&rs=1'
                ],
                index: 0

            },
            methods: {
                prev: function () {
                    this.index--
                },
                next: function () {
                    this.index++
                }

            }
        })
    script>
body>

html>

7.v-for

①指令作用是根据数据生成列表结构
②经常和数组一起使用
③语法:(item,index) in 数据
④item和index可以结合其他指令一起用
⑤数组长度的更新会同步刷新到页面上,是响应式的
⑥在使用v-for时,v-bind:key不能省略,一般简写为 :key=“index”
vue框架_第5张图片

<body>
    <div id="app">
        <li v-for="(item,index) in arr">下标值为{{index}}的数据为{{item}}li>
        <h2 v-for="(item,index) in color">{{item.name}}h2>
        <input type="button" @click='add' value="add">
        <input type="button" @click='remove' value="remove">
    div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                arr: [1, 2, 3, 4, 5],
                color: [{
                    name: 'red'
                }, {
                    name: 'origin'
                }, {
                    name: 'yellow'
                }]
            },
            methods: {
                add: function () {
                    this.color.push({
                        name: 'others'
                    })
                },
                remove: function () {
                    this.color.pop()
                }
            }
        })
    script>
body>

vue框架_第6张图片

8.v-model

①v-model指令的作用是快捷获取和设置表单元素的值
②绑定的数据会和表单元素值相关联,一边修改,两边都会同时变化

<body>
    <div id="app">
        <input type="button" value="change" @click="change">
        <input type="text" v-model="message">
        <h2 v-text='message'>h2>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '青空结界'
            },
            methods: {
                change: function () {
                    this.message = '紫呜怜'
                }
            }
        })
    script>
body>

vue框架_第7张图片
案例-小黑记事本

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            background-color: #F3F3F3;
        }

        .title {
            width: 300px;
            height: 60px;
            margin: 100px auto 30px;
            line-height: 60px;
            text-align: center;
            font-size: 36px;
            color: orange;

        }

        .content {
            width: 360px;
            /* height: 200px; */
            background-color: #fff;
            margin: 0 auto;
            box-shadow: 5px 5px 5px #ccc;
        }

        .content input {
            width: 350px;
            height: 35px;
            border: none;
            outline: none;
            box-shadow: 2px 5px 5px #ccc;
            font-size: 18px;
            padding-left: 10px;

        }

        .lr {
            width: 100%;
            height: 25px;
            font-size: 8px;
            color: #999;
        }

        .left {
            float: left;
            width: 60px;
            padding-left: 5px;
            margin-top: 5px;
        }

        .right {
            float: right;
            width: 35px;
            margin-top: 5px;
        }

        .content p {
            width: 345px;
            height: 40px;
            /* background-color: pink; */
            font-size: 20px;
            color: #999;
            line-height: 40px;
            padding-left: 15px;
            border-bottom: 1px dashed #ccc;
        }

        .aaa {
            float: right;
            display: none;
            text-decoration: none;
            font-size: 14px;
            color: #999;
            padding-right: 15px;
        }

        .content p:hover .aaa {
            display: block;
        }
    style>
head>

<body>
    <div id="app">
        <div class="title">
            小黑记事本
        div>
        <div class="content">
            <input type="text" @keyup.enter="add" v-model="message" placeholder="请输入内容" autofocus="autofocus"
                autocomplete="off">
            <p v-for="(item,index) in arr">{{index+1}}.    {{item}}
                <a href="javascript:;" class="aaa" @click="remove(index)">xa>
            p>
            <div class="lr" v-show="arr.length>0">
                <div class="left">{{arr.length}} itemsdiv>
                <div class="right" @click="clear">Cleardiv>
            div>
        div>

    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: '',
                arr: []
            },
            methods: {
                add: function () {
                    this.arr.push(this.message)
                    this.message = ''
                },
                remove: function (p1) {
                    this.arr.splice(p1, 1)
                },
                clear: function () {
                    this.arr = []
                }
            }
        })
    script>
body>

html>

在这里插入图片描述

9.v-cloak

本质是一个特殊属性,vue实例创建并接管容器后,会删掉v-clock属性
配合css可以解决当网速过慢的时候页面出现{{xxx}}的问题
vue框架_第8张图片

9.v-once

①v-once在所在节点初次渲染后,就视为静态内容了
②以后数据无论发生任何变化都不会引起v-once所在结构的改变

<body>
    <div id="app">
        <h2 v-once>初始化n值为{{n}}h2>
        <h2>现在的n值为{{n}}h2>
        <button @click='n++'>点我n+1button>
    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                n: 1
            }
        })
    script>
body>

vue框架_第9张图片

10.v-pre

v-pre可以跳过所在节点的编译过程,适用于无需解析渲染的节点
在这里插入图片描述

3.网络应用

1.axios

功能强大的网络请求库
①需要先导入再使用
②使用get或post方法发送对应的请求
③then方法的回调函数会在请求成功或失败时触发
④通过回调函数获取相应内容或错误信息
vue框架_第10张图片

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <input type="button" value="get" class="get">
    <input type="button" value="post" class="post">
    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    <script>
        document.querySelector('.get').onclick = function () {
            axios.get('https://autumnfish.cn/api/joke/list?num=3').then(data => {
                console.log(data);
            }).catch(err => {
                console.log(err);
            })
        }
        document.querySelector('.post').onclick = function () {
            axios.post('https://autumnfish.cn/api/user/reg', {
                username: "图坦卡蒙"
            }).then(data => {
                console.log(data);
            }).catch(err => {
                console.log(err);
            })
        }
    script>
body>

html>

2.axios和vue结合

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <input type="button" value="get" @click='getjoke'>
        <p v-text='joke'>p>
    div>


    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                joke: ''
            },
            methods: {
                getjoke: function () {
                    axios.get('https://autumnfish.cn/api/joke').then(data => {
                        console.log(data.data);
                        this.joke = data.data
                    }).catch(err => {
                        console.log(err);
                    })
                }
            }
        })
    script>
body>

html>

vue全家桶

是一套用于构建用户界面的渐进式JavaScript框架
特点:
①采用组件化模式,提高代码复用率,让代码更好维护
②声明式编码,让编码人员无需直接操作dom,提高开发效率
(命令式编码就是写一句动一下,声明式,写一下整套流程动到结束)
③使用虚拟DOM和优秀的Diff算法,尽量复用DOM节点
vue框架_第11张图片

1.vue核心

1.1初识vue

<body>
    <div id="app">
        <h2>{{name}}h2>
    div>
    <script src="../js/vue.js">script>
    <script>
        Vue.config.productionTip = false //阻止vue启动时生成提示
        new Vue({
            el: '#app',
            data: {
                name: '笨蛋老虎'
            }
        })
    script>
body>

注意:
①阻止提示可以修改config的属性
②可以直接创建Vue对象,无需赋值给变量
③如果有两个相同的容器,vue只负责第一个,第二个不做渲染
即vue实例与容器是一一对应的,不可一对多,也不能多对一
④双花括号里只能放表达式,才能被解析,否则只能被视作字符串

1.2模板语法

有插值语法({{ }})和指令语法(v-)两种
其他指令看上面vue简介
注意:
①v-model只能用在表单类元素上,即有value属性的表单元素

1.3el和data的两种写法

1.el
①创建vue时配置

new Vue({
    el: '#app',
    data: {
        name: '笨蛋老虎'
    }
})

②先创建,后配置

var app = new Vue({
    // el: '#app',
    data: {
        name: '笨蛋老虎'
    }
})
app.$mount('#app')

两种方式想用哪个都可以

2.data
①对象式
var app = new Vue({
// el: ‘#app’,
data: {
name: ‘笨蛋老虎’
}
})
②函数式
var app = new Vue({
el: ‘#app’,
data: function () {
return {
name: ‘笨蛋老虎’
}
}
})

注意:
①在使用组件的时候必须要用函数式
②函数式中的函数调用者是vue,this指向vue实例,所以不要用箭头函数

1.4MVVM模型

vue框架_第12张图片
所有写在data中的数据都会出现在vm模型(vue实例)上,模板语法实际上是去读取vm模型,所以模板语法可以读取到vue实例中出现的所有元素
vue框架_第13张图片

1.5数据代理

1.Object.defineProperty函数
3个参数分别是,对象,属性,属性值,用于给对象添加属性
特点
①添加的值不参与遍历(枚举)
②添加的值不能修改和删除

<script>
    let person = {
        name: '七七',
        sex: '女'
    }
    Object.defineProperty(person, 'age', {
        value: 345
    })
    console.log(person);
    person.sex = 'nv'
    person.age = 777
    console.log(person);
</script>

解决办法:

Object.defineProperty(person, 'age', {
    value: 345,
    enumerable: true, //控制属性是否可以枚举,默认值为false
    writable: true, //控制属性是否可以被修改,默认值为false
    configurable: true //控制属性是否可以被删除,默认值为false
})

get和set函数
如果直接在person里让age等于number,可以成功获取number值,但是number之后修改,age不会跟着变化,
采用get方法,可以读取的同时获取,实现同步修改

        let number=18
        let person = {
            name: '七七',
            sex: '女'
        }
Object.defineProperty(person, 'age', {

    //当有人读取age属性时,get函数就会被调用,返回age的值
    get(){
        console.log('有人读取age属性');
        return number
    },
    //当有人修改age属性时,set函数就会被调用,value就是修改后的值
    set(value){
        console.log('有人修改了age属性',value);
        number=value
    }
})

2.数据代理是什么
定义:通过一个对象代理对另一个对象中属性的操作
举个例子

<script>
    let obj = {
        x: 100
    }
    let obj2 = {
        y: 200
    }
    Object.defineProperty(obj2, 'x', {
        get() {
            return obj.x
        },
        set(value) {
            obj.x = value
        }
    })
</script>

vue框架_第14张图片
3.vue中应用数据代理
vue实例中的属性就是用的数据代理,每当获取vue中某属性时,就会触发get方法,获取到data中的对应属性,vue中对应属性改变后触发set修改data中的数据

vue中的data就是vue中的_data

简单来说就是,name,address属性存在于vue中的_data属性中,然后用数据代理在vue中用同名属性代理操作_data中的属性,页面渲染用的就是vue中的代理属性,每个代理属性都有它自己的get和set方法
vue框架_第15张图片

1.6事件处理

1.基本使用
看上面v-on
注意:
①如果要传其他参数又要传event,可以在传的时候用$event占个位置,表示传的是event
vue框架_第16张图片
②methods是没有做数据代理的

2.事件修饰符-前三个常用
①prevent:阻止默认事件
②stop:阻止冒泡事件
③once:事件只触发一次
④capture:使用时间的捕获模式
⑤self:只有event.target是当前操作的元素时才触发事件
⑥passive:事件的默认行为立即执行,无需等待时间回调函数执行完毕

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        .maopao {
            height: 100px;
            background-color: pink;
        }

        .wheel {
            height: 200px;
            width: 150px;
            background-color: skyblue;
            overflow: auto;

        }

        .wheel li {
            height: 100px;
            width: 150px;
        }
    style>
    
head>

<body>
    <div id="app">
        
        <a href="www.baidu.com" @click.prevent='alerting'> 点我a>
        
        <div @click='alerting' class="maopao">
            <button @click.stop='alerting'>阻止冒泡事件button>
        div>
        
        <button @click.once='alerting'>只触发一次button>
        
        <div @click.capture='alerting' class="maopao">
            <button @click='alerting'>使用捕获模式button>
        div>
        
        
        <div @click.self='alerting' class="maopao" style="margin-top: 10px;">
            <button @click='alerting'>selfbutton>
        div>
        
        <div class="wheel" @wheel.passive='wheel'>
            <li>#li>
            <li>#li>
            <li>#li>
            <li>#li>
        div>

    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {
                alerting: function () {
                    alert('提示信息')
                },
                wheel: function () {
                    for (let i = 0; i < 10000; i++) {
                        console.log('#');
                    }

                }
            }
        })
    script>
body>

html>

3.键盘事件keyup.enter
vue框架_第17张图片
自定义按键别名

Vue.config.keyCodes.huiche=13

1.7计算属性

注意:一旦data中数据发生变化,页面就会重新解析渲染
1.使用插值实现姓名案例

<body>
    <div id="app">
        姓: <input type="text" v-model='xing'><br>
        名: <input type="text" v-model='ming'><br>
        全称: <span>{{xing.slice(0,2)}}-{{ming}}span>
    div>
    <script src="../../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                xing: '',
                ming: ''
            }
        })
    script>
body>

实现姓名重组,并且用slice限制姓的长度
vue框架_第18张图片
2.methods实现姓名案例

<body>
    <div id="app">
        姓: <input type="text" v-model='xing'><br>
        名: <input type="text" v-model='ming'><br>
        全称: <span>{{fullName()}}span>
    div>
    <script src="../../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                xing: '',
                ming: ''
            },
            methods: {
                fullName: function () {
                    return this.xing + '-' + this.ming
                }
            }
        })
    script>
body>

3.计算属性实现姓名案例
注意
①计算属性本身不存在,要通过已有属性计算得来
②底层借助Object。defineproperty方法提供的get和set
③get仅在初次读取数据和依赖数据发生改变时执行
④当执行一次歌天后,计算结果会缓存,后面再有使用计算属性的,直接用缓存值,实现了复用
⑤计算属性没使用数据代理,直接出现在vm上,直接读取使用即可
⑥当计算属性被修改时,要调用set方法修改依赖属性

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        姓: <input type="text" v-model='xing'><br>
        名: <input type="text" v-model='ming'><br>
        全称: <span>{{fullName}}span>
    div>
    <script src="../../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                xing: '',
                ming: ''
            },
            computed: {
                fullName: {
                    get() {
                        return this.xing + '-' + this.ming
                    },
                    set(value) {
                        let arr = value.split('-')
                        this.xing = arr[0]
                        this.ming = arr[1]
                    }
                }
            }
        })
    script>
body>

html>

vue框架_第19张图片
计算属性简写

fullName(){
    return this.xing + '-' + this.ming
}

只有在只需要get方法时才可简写,直接写成es6简写方法形式

1.8监视属性watch

①当被监视的属性发生改变时,回调函数自动调用
②监视的属性必须存在才能进行监视
③有两种写法,一种创建vue时传入watch配置,一种通过vm.$watch监视

<body>
    <div id="app">
        <h2>今天的天气很{{info}}h2>
        <button @click='change'>切换天气button>
    div>
    <script src="../../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                ishot: true
            },
            computed: {
                info() {
                    return this.ishot ? '炎热' : '凉爽'
                }
            },
            methods: {
                change() {
                    this.ishot = !this.ishot
                }
            },
            watch: {
                ishot: {
                    immediate: true, //初始化时让handler执行一下
                    handler(newValue, oldValue) {
                        console.log('属性发生了改变', oldValue, newValue);
                    }
                }

            }
        })
    script>
body>

vue框架_第20张图片
另一种写法

vm.$watch('ishot', {
    immediate: true, //初始化时让handler执行一下
    handler(newValue, oldValue) {
        console.log('属性发生了改变', oldValue, newValue);
    }
})

深度监视
①监视多极结构中的某个属性
属性中的属性要监视用‘a.b’,记得加引号

watch: {
    'ishot.a:' {
        immediate: true, //初始化时让handler执行一下
        handler(newValue, oldValue) {
            console.log('属性发生了改变', oldValue, newValue);
        }
    }

}

②监视多级属性中所有的属性,配置deep:true

watch: {
    ishot: {
        deep:true,
        immediate: true, //初始化时让handler执行一下
        handler(newValue, oldValue) {
            console.log('属性发生了改变', oldValue, newValue);
        }
    }

}

简写

ishot(newValue, oldValue) {
    console.log('属性发生了改变', oldValue, newValue);
}
vm.$watch('ishot', 
    function(newValue, oldValue) {
        console.log('属性发生了改变', oldValue, newValue);
    }
)

简写的缺点就是不能配置immediate和deep

computed和watch之间的区别
vue框架_第21张图片

1.9class与style样式绑定

和上面差不多
绑定class样式,basic确定,另一个不确定,用v-bind在这里插入图片描述

style
vue框架_第22张图片
注意style属性名写法,-要去掉,后面单词首字母大写
vue框架_第23张图片

1.10列表过滤

有两种方式完成,watch和computed,当两者都能实现时,优先使用computed
①监视属性

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>watch实现title>
head>

<body>
    <div id="app">
        <input type="text" v-model='keyword'>
        <li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}li>
    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                keyword: '',
                persons: [{
                        id: '001',
                        name: '天王星',
                        sex: '女'
                    },
                    {
                        id: '002',
                        name: '冥王星',
                        sex: '男'
                    },
                    {
                        id: '003',
                        name: '大金星',
                        sex: '女'
                    },
                    {
                        id: '004',
                        name: '王天王',
                        sex: '男'
                    },
                    {
                        id: '005',
                        name: '冥御史',
                        sex: '男'
                    },
                ],
                filpersons: []
            },
            watch: {
                keyword: {
                    immediate: true,
                    handler(val) {
                        this.filpersons = this.persons.filter(p => {
                            return p.name.includes(val)
                        })
                    }
                }
            }
        })
    script>
body>

html>

②计算属性

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>watch实现title>
head>

<body>
    <div id="app">
        <input type="text" v-model='keyword'>
        <li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}li>
    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                keyword: '',
                persons: [{
                        id: '001',
                        name: '天王星',
                        sex: '女'
                    },
                    {
                        id: '002',
                        name: '冥王星',
                        sex: '男'
                    },
                    {
                        id: '003',
                        name: '大金星',
                        sex: '女'
                    },
                    {
                        id: '004',
                        name: '王天王',
                        sex: '男'
                    },
                    {
                        id: '005',
                        name: '冥御史',
                        sex: '男'
                    },
                ],
            },
            computed: {
                filpersons() {
                    return this.persons.filter(p => {
                        return p.name.includes(this.keyword)
                    })
                }
            }
        })
    script>
body>

html>

1.11列表排序

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>watch实现title>
head>

<body>
    <div id="app">
        <input type="text" v-model='keyword'>
        <button @click='sortnum=2'>升序button>
        <button @click='sortnum=1'>降序button>
        <button @click='sortnum=0'>原顺序button>
        <li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}-{{item.age}}li>
    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                keyword: '',
                sortnum: 0,
                persons: [{
                        id: '001',
                        name: '天王星',
                        sex: '女',
                        age: 19
                    },
                    {
                        id: '002',
                        name: '冥王星',
                        sex: '男',
                        age: 25
                    },
                    {
                        id: '003',
                        name: '大金星',
                        sex: '女',
                        age: 23
                    },
                    {
                        id: '004',
                        name: '王天王',
                        sex: '男',
                        age: 18
                    },
                    {
                        id: '005',
                        name: '冥御史',
                        sex: '男',
                        age: 26
                    },
                ],
            },
            computed: {
                filpersons() {
                    const arr = this.persons.filter(p => {
                        return p.name.includes(this.keyword)
                    })
                    if (this.sortnum) {
                        arr.sort((p1, p2) => {
                            return this.sortnum === 2 ? p1.age - p2.age : p2.age - p1.age
                        })
                    }
                    return arr
                }
            }
        })
    script>
body>

html>

vue框架_第24张图片

1.12vue如何检测数据改变的

1.如何检测对象
靠set方法
Vue.set()也可用vm.$set()
这种方法添加的属性也有get和set方法
局限性:不能直接给vm或data添加属性,只能给data里属性及以下添加属性

2.如何检测对象
数组内元素是没有get,set的,通过赋值运算无法被vue检测到,但是通过push,pop等方法修改数组元素时,依旧可以检测到改变,因为这些方法是被vue包装过的,不是原汁原味的方法,通过这些方法检测变化

总结
vue框架_第25张图片

1.13收集表单数据

1.使用v-model获取input和select,textarea类型(即有value值的项目)
①如果是text,password等有输入框的,直接v-model获取value值
②单选框radio,要给每个选项设置好value值
③checkbox多选框,除了设置value值,还要把初始值设置为数组,否则收集的是checked布尔值
④textarea,select等设置上value即可

②修饰符-加在v-model后,如v-model.trim=‘’
①lazy:失去焦点再收集数据
②number:输入字符转为有效的数字
③trim:输入首尾空格过滤

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <form action="">
            账号:<input type="text" v-model='username'><br><br>
            密码:<input type="password" v-model='password'><br><br>
            性别:
            男<input type="radio" name="sex" v-model='sex' value="male"><input type="radio" name="sex" v-model='sex' value="female"><br><br>
            爱好:
            吃饭:<input type="checkbox" v-model='hobby' value="1">
            睡觉:<input type="checkbox" v-model='hobby' value="2">
            打豆豆:<input type="checkbox" v-model='hobby' value="3"><br><br>
            所属校区:
            <select name="" id="" v-model='fangxiang'>
                <option value="">请选择校区option>
                <option value="dong">option>
                <option value="nan">option>
                <option value="xi">西option>
                <option value="bei">option>
            select><br><br>
            其他:
            <textarea name="" id="" cols="30" rows="10" v-model='other'>textarea><br><br>
            <input type="checkbox">阅读并接受用户协议
            <input type="button" value="提交" @click='tijiao'>
        form>
    div>
    <script src="../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                username: '',
                password: '',
                sex: 'male',
                hobby: [],
                fangxiang: '',
                other: ''
            },
            methods: {
                tijiao() {
                    console.log(JSON.stringify(this._data));
                }
            }
        })
    script>
body>

html>

vue框架_第26张图片

1.14过滤器属性

过滤器本质是一个函数,对要显示的的数据做一些简单处理再显示
注册过滤器
①像methods那样,作为vue实例的一个属性设置上,不过filters是局部的,只有当前vue可以用
②Vue.filter(name,callback)
其他
①过滤器可以接收额外参数,多个过滤器也可以串联
②没有改变原来的数据,而是产生新的数据
③插值语法和v-bind可以使用过滤器,其他的不行

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <h2>时间戳{{now}}h2>
        
        <h2>computed实现{{comnow}}h2>
        
        <h2>methods实现{{metnow()}}h2>
        
        <h2>filters实现{{now | filnow()}}h2>
        
        <h2>filters传参{{now | filnow('YYYY-MM-DD')}}h2>
        
        <h2>filters串联{{now | filnow('YYYY-MM-DD') |filslice()}}h2>
        
        <h2>filter全局{{now | filnow('YYYY-MM-DD') |fslice()}}h2>
    div>
    <script src="../js/vue.js">script>
    <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js">script>
    <script>
        Vue.filter('fslice', function (val) {
            return val.slice(0, 4)
        })
        var vm = new Vue({
            el: '#app',
            data: {
                now: 1638797329896
            },
            computed: {
                comnow() {
                    return dayjs(this.now).format('YYYY-MM-DD HH:mm:ss')

                }
            },
            methods: {
                metnow() {
                    return dayjs(this.now).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            filters: {
                filnow(val, src = 'YYYY-MM-DD HH:mm:ss') {
                    return dayjs(val).format(src)
                },
                filslice(val) {
                    return val.slice(0, 4)
                }
            }
        })
    script>
body>

html>

vue框架_第27张图片

1.15自定义指令

①在directives属性中定义自定义指令
②有两种方式可以定义,分别为函数式和对象式
③函数式传入的两个参数,element就是所在的dom元素,binding则是绑定的参数详细信息
④自定义指令函数式只有在指令与元素绑定成功时和指令所在模板被重新解析时
⑤对象式在对象内存放多个函数,分别在三个不同的时刻调用不同的函数,函数式相当于对象式的阉割版只在两个不同时刻调用
⑥,命名用多个单词时用-链接,命名中出现-时可以用引号把名字包起来
⑦全局自定义指令Vue.directtive(name,对象或者函数)

<body>
    <div id="app">
        <h2>当前n值为:<span v-text='n'>span>h2>
        <h2>放大后n值为:<span v-big='n'>span>h2>
        <button @click='n++'>n++button>
        <input v-fbind:value="n" type="text">
    div>
    <script src="../../js/vue.js">script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                n: 1
            },
            directives: {
                big(element, binding) {
                    element.innerText = binding.value * 10
                },
                fbind: {
                    //指令与元素绑定时
                    bind(element, binding) {
                        element.value = binding.value
                    },
                    //指令所在元素被插入页面时
                    inserted(element, binding) {
                        element.focus()
                    },
                    //指令所在的模板被重新解析时
                    update(element, binding) {
                        element.value = binding.value
                    }
                }
            }
        })
    script>
body>

vue框架_第28张图片

1.16生命周期

mounted函数,与data,methods等同级
在vue完成模板的解析并把初始的真实dom元素放入页面后,再调用mouted,且只调用一次
①生命周期又名生命周期回调函数,生命周期函数,生命周期钩子
②是vue在关键时刻帮我们调用的一些特殊名称的函数
③生命周期函数的名字不可更改,但具体的内容是根据需求写的
④生命周期函数中的this指向是vm或组件实例对象

<body>
    <div id="app">
        <h2 :style="{opacity}">学习Vue-ingh2>
    div>
    <script src="../js/vue.js">script>
    <script>
        new Vue({
            el: '#app',
            data: {
                opacity: 1
            },
            mounted() {
                setInterval(() => {
                    this.opacity -= 0.01
                    if (this.opacity <= 0) this.opacity = 1
                }, 16)
            },
        })
    script>
body>

生命周期钩子总结
常用的生命周期钩子
①mounted:发送ajax请求,启动定时器,绑定自定义事件订阅消息等初始化操作
②beforeDestroy:清除定时器,解绑自定义事件,取消订阅消息等收尾工作

关于销毁Vue实例
①销毁后借助Vue开发者工具看不到任何信息
②销毁后自定义事件会失效,但原生DOM事件依然有效
③一般不会在beforeDestory操作数据,即便操作了也不会触发更新流程

2.vue组件化编程

模块:向外提供一定功能的js程序,一般为一个js文件
组件:实现应用中局部功能代码和资源的集合
优点:复用代码,简化项目编码。提高编码效率
模块化:当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用
组件化:当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用

单文件组件:一个文件中只包含一个组件(用的多,条理清晰)
非单文件组件:一个文件中包含n个组件

1.非单文件组件

组件创建时不写el,以后哪里需要往哪搬
组件里的数据要用函数式,那么一个组件被使用多次是不会互相干扰的

1.组件的创建使用

1.创建组件
const school=Vue.extend({ })
2.注册组件
局部注册
components:{
school:school}
全局注册
Vue.component(组件名,组件)
3.编写组件标签
vue框架_第29张图片

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        
        <school>school>
        <student>student>
        <hello>hello>
    div>
    <div id="root">
        <hello>hello>
    div>
    <script src="../../js/vue.js">script>
    <script>
        //全局注册
        const hello = Vue.extend({
            template: `        
            

{{helloname}}

`
, data() { return { helloname: 'hello' } }, }) Vue.component('hello', hello) //第一步-创建组件 const school = Vue.extend({ template: `

{{schoolname}}

{{address}}

`
, data() { return { schoolname: '灵帝国', address: '九重岛天' } }, }) const student = Vue.extend({ template: `

{{studentName}}

`
, data() { return { studentName: '王玄清', age: 18 } }, }) new Vue({ el: '#app', //第二步-注册组件 components: { school: school, //常规形式 student //简写形式,key与value相同时用 } }) new Vue({ el: '#root' })
script> body> html>

vue框架_第30张图片

2.注意事项

①命名官方推荐
一个单词组成:首字母大小写都行
多个单词组成:第一种my-school,记得在vue里用引号引住,第二种MySchool,需要有Vue脚手架
②关于组建标签的写法
第一种
第二种需要vue脚手架
③组件创建简写const school ={data(){return}}

3.组件的嵌套

把一个组件写在另一个组件的components里面,同时组件标签页也要写在另一个组件模板里面
要注意顺序问题,子组件在定义时要在父组件的前面
通常嵌套都有一个领头的,vm之下,其他组件之上,然后在vm的template中放领头的组件标签,就可以实现容器内干干净净,标准化开发都是这么干的

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">

    div>
    <script src="../../js/vue.js">script>
    <script>
        //第一步-创建组件
        const student = Vue.extend({
            template: `        
            

{{studentName}}

`
, data() { return { studentName: '王玄清', age: 18 } }, }) const school = Vue.extend({ template: `

{{schoolname}}

{{address}}

`
, data() { return { schoolname: '灵帝国', address: '九重岛天' } }, components: { student } }) new Vue({ el: '#app', template: ``, components: { school } })
script> body> html>

注意:template中如果只有一个标签可以只放该标签,如果有多个,一定要把多个放在一个div里面

4.VueComponent构造函数

1.组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,而是vue.extend生成的
2.我们只需要写,Vue解析时会帮我们创建school的组件实例对象,即Vue帮我们执行new VueComponent(options)
3.每一次调用extend,就会返回一个全新的VueComponent构造函数,当场定义当场返回
4.关于this指向
组件配置中,data,methods等this指向均为VueComponent实例对象
Vue实例配置中,data,methods等this指向均为Vue实例对象
5.VueComponent实例对象简称vc,vue实例对象简称vm

5.一个重要的内置关系

vm和vc不完全相同,vc有的vm都有,vm有的vc不一定有,而且vc中的一些属性要用函数式
prototype:显式原型属性
proto:隐式原型属性
他俩指向了实例的原型对象
在这里插入图片描述
在判断的时候要把VueComponent改成对应的school或其他具体组件
vue框架_第31张图片

2.单文件组件

<template>
  
  <div class="demo">
    <h2>{{ schoolname }}h2>
    <h2>{{ address }}h2>
  div>
template>
<script>
// 组件的交互
export default {
  name: "School",
  data() {
    return {
      schoolname: "灵帝国",
      address: "九重岛天",
    };
  },
};
script>
<style lang="">
/* 组件的样式 */
style>

3.vue脚手架/CLI

是官方提供的标准化开发工具/平台

1.脚手架的使用

npm i -g @vue/cli
vue框架_第32张图片
62集有详细步骤

2.render函数

render:h=>h(App)
是一个箭头函数,h是传入的参数,是一个函数,用来注册组件和生成元素,就不用tempplate和components了
vue框架_第33张图片

3.默认配置的修改

public文件夹和main.js不能修改,修改了就运行不起来了
vue inspect > output.js
可以把所有默认配置输出为一个js文件用于浏览,但修改了没用

关闭语法检查和修改一些元素可以在cli中查
在这里插入图片描述

4.ref属性

和id属性类似,可以辅助获取dom元素
在vue文件中this指向就是该组件
vue框架_第34张图片
vue框架_第35张图片

5.props配置项(和data,methods等同级)

注意:同时使用多个同一组件实例,每个组件实例之间互不影响
使用props可以在父级传参数,然后在子级组件用props接收使用,传过来的是字符串,可以通过props里的type修改,传入的数值尽可能不要改,可以改,但会有警示
要改的话就定义一个参数等于这个值,然后用新参数来改
vue框架_第36张图片

6.Mixin配置项-混入

vue框架_第37张图片
混入的数据方法如果和原来的冲突,那么以原来的为主,如果有mounted,来者不拒,都要

7.插件

vue框架_第38张图片

8.scoped样式

写在所有组件里的style样式最后都会解析在一个文件里,会造成命名冲突,
于是用到了scoped,单词作用域的意思,原理就是给不同的style添加随机生成的属性,这样就
让样式在局部生效,防止冲突
写法:

9.案例

vue框架_第39张图片
遇到的问题
1.uuid用于生成全球唯一id,nanoid是它的缩小版
2.数据子传父,父给子传一个函数,然后子调用这个函数
3.父传子数据时记得带:即v-bind,这样才能传表达式或者函数,否则传的都是字符串
4.组件命名要用驼峰法,而且不不能是一个单词要是XxxXxxx
5.组件注册了就要用
6.v-for循环时记得绑定key
7.判断方法,当触发方法时进行一个判断,点确定就继续执行
在这里插入图片描述
8.reduce,用于数组的条件计数
9.使用v-show决定底部的显示与隐藏
10.删除数组中指定位置往后的元素,splice(index,)

9.1自定义组件事件

实现子组件给父组件传递信息,有两种方法
1.使用props,父亲给孩子传一个函数,然后孩子props接收,调用此函数传参
2.父亲在孩子的组件实例绑定一个自定义事件, 然后在子组件的方法中调用this. e m i t ( " 自定义组件名 " ,参数(可以传很多参数) ) 3. 也是用 t h i s . emit("自定义组件名",参数(可以传很多参数)) 3.也是用this. emit("自定义组件名",参数(可以传很多参数))3.也是用this.emit,不过是在绑定自定义事件时使用mounted中this.$refs.shuru.$on("chuancan", this.huoqu);
好处是可以设置延时等操作
**注意:**给组件绑定原生事件也会被默认认为是自定义事件,除非加上.native,如@click.native=

9.2自定义组件事件的解绑

用this. o f f t h i s . off this. offthis.off()----全部解绑
this. o f f ( a ) − − − − 解绑指定事件 t h i s . off(a)----解绑指定事件 this. off(a)解绑指定事件this.off([a,b])----解绑多个事件

组件的销毁this.$destroy()
销毁之后组件及子组件的自定义事件都不奏效了

9.3全局事件总线

简单来说,就是为vue的原型对象添加一个vue实例对象(因为这个实例对象中有着 o n , on, on,off等方法)
因为每个组件实例对象往上追溯都是vue,也就是说每个实例对象都继承了这个组件实例对象,这个对象也被称为事件总线,
接下来当两个组件想要通信时,接收方为总线绑定自定义事件,发送方调用该自定义事件。
(可用于任意组件间通信)
vue框架_第40张图片
注意:在绑定事件的组件里,在beforeDestroy钩子中,要解绑该组件用到的事件,这样组件销毁后,总线中的事件也会跟着销毁

父传子:用props
子传父:用props,自定义事件都可
同级传,孙传爷:用全局事件总线

9.4消息订阅与发布

也适用于任意组件通信,和总线几乎一摸一样,
且总线是vue本身的,订阅是外部库,所以大多时候用的都是总线
vue框架_第41张图片
注意:接收数据时,会接受两个参数,第一个是订阅名,第二个才是传的参数
vue框架_第42张图片

9.5vue中的动画

为要添加动画的元素包裹上transition

<transition name="dong" appear>
  <div class="ahh" v-show="ist">{{ msg }}</div>
</transition>

再设置动画
transition上的name就是下面动画标签的前缀,后缀是vue固定的
这样,当元素显隐的时候,vue会自动给元素添加对应的动画标签

.dong-enter-active {
  animation: dong 1s;
}
.dong-leave-active {
  animation: dong 1s reverse;
}
@keyframes dong {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

注意:
①和tempplate一样,解析的时候就消失了
②appear是为了刷新的时候自动触发一次出现动画

9.6vue中的过渡

和动画类似,方法为

.guo-enter,
.guo-leave-to {
  transform: translateX(-100%);
}
.guo-enter-to,
.guo-leave {
  transform: translateX(0);
}
.guo-enter-active,
.guo-leave-active {
  transition: 1s;
}

在整个进入过程中,transition标签一共给元素添加了三个样式
.v-enter进入的起点
.v-enter-active进入的过程中
.v-enter-to进入的终点
来控制整个动画

注意:transition标签只能控制一个元素的动画
控制多个要用transition-group
但只能控制相同动画元素

第三方动画库:animate.style

4.vue中的ajax

4.1代理服务器(解决跨域)

1.代理服务器
vue请求服务器一般使用axios
1.创建请求组件(记得先安装axios再引入)(npm i axios)(import axios from “axios”

<template>
  <button @click="qingqiu">请求学生数据</button>
</template>

<script>
import axios from "axios";
export default {
  methods: {
    qingqiu() {
      axios.get("http://localhost:8080/students").then(
        (response) => {
          console.log("yes", response.data);
        },
        (error) => {
          console.log("no", error.message);
        }
      );
    },
  },
};
</script>

<style>
</style>

注意:因为使用了代理服务器,所以目标地址是代理服务器的端口号
2.配置代理服务器
在vue.config.js里,地址写目标服务器地址

  devServer: {
    proxy:'http://localhost:5000'
  }

3.补充:创建一个服务器
要保证电脑已经安装了node,且文件安装了express

const express = require("express")
const app = express()
app.use((request,response,next) => {
    console.log("有人请求1了");
    next()
})

app.get('/students', (request,response) => {
    const students = ["这是数据"]
    response.send(students)
})

app.listen(5000, (err) => {
    if(!err) console.log("启动成功");
})

这种代理服务器不灵活,且当本地有对应数据时,就不会去请求其他服务器,因此有第二种方法更灵活,并且第二种方法有可以配置多个代理

2.代理服务器2

 devServer: {
    proxy: {
      // 这个名字可以不用api,改成自己想要的
      '/api': {
        // 路径地址
        target: 'http://localhost:5000',
        // 路径置换,因为请求那里有/api,所以要去掉api
        pathRewrite: { '^/api': '' },
        //  这两个可以不写
        ws: true,
        changeOrigin:true
      }
    }
  }

这要在端口号后加上代理名称

 methods: {
    qingqiu() {
      axios.get("http://localhost:8080/api/students").then(
        (response) => {
          console.log("yes", response.data);
        },
        (error) => {
          console.log("no", error.message);
        }
      );
    },
  },

vue框架_第43张图片
vue框架_第44张图片

4.2插槽

4.2.1.默认插槽

父组件

<template>
  <div class="main">
    <CateGory title="美食">
      <img
        src="https://s.cn.bing.net/th?id=OIP-C.ku8Xxe4A_gkLMC1bWlb5FAHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2"
        alt=""
      />
    </CateGory>
    <CateGory title="游戏">
      <ul>
        <li v-for="(item, index) in game" :key="index">{{ item }}</li>
      </ul>
    </CateGory>
    <CateGory title="电影">
      <video
        autoplay
        controls
        src="https://webstatic.mihoyo.com/upload/op-public/2022/03/08/942f3c2ac510dc3188449e82c4c3dd06_2539121796737105485.mp4"
      ></video>
    </CateGory>
  </div>
</template>

子组件

<template>
  <div class="container">
    <h2>{{ title }}展示平台</h2>
    <slot>啥也没传就展示这个</slot>
  </div>
</template>

这个slot就是插槽,当组件实例那边传过来内容,就放在插槽位置,不然就显示插槽内容
style样式写在子组件父组件都行
写在父组件,父组件渲染样式后再发过去
写在子组件,发过来子组件自己渲染

4.2.2具名插槽

注意:
①具名插槽,vue2支持在标签内写插槽名,如


vue3不支持了,必须要在外面套一层template,在template里写名字,

  <template #two>
    <a href="">美食party</a>
  </template>

②具名写法
在子组件slot添加name属性第二个插槽
在父组件引入

  <template two>
    <a href="">美食party</a>
  </template>

简写就是#two

4.2.3作用域插槽

适用于数据在子组件,用同一个数据生成多个结构的场景
父组件
scope用来接收子组件传的数据
vue框架_第45张图片
子组件
给父组件用到的slot传参
vue框架_第46张图片

5.vuex

5.1vuex简述

概念:是一个在vue中实现集中式状态/数据管理的一个vue插件,对多个组件的共享状态进行集中式管理(读/写)
用处:可用于任意组件间通信
使用场景:多组件共享状态
vue框架_第47张图片
actions就如同服务员,用来写条件判断等逻辑
mutations如同后厨,就写具体操作
如果是纯纯的操作,就直接commit调用mutations
有点业务逻辑的就继续通过actions

5.2搭建vuex环境

1.安装vux
npm i vuex@next
2.创建vuex文件
在src/store/index.js引入vuex,之后创建一个vuex实例,进行state等项目的配置
vue框架_第48张图片

3.项目引入
在main.js里import这个index.js,并use()它
vue框架_第49张图片
注意:①use写在mount前面,mount写在最后
②引入时写到store即可,他会自动识别文件
4.vuex使用
在组建中直接使用this.$store就可用了
如果是在setup中使用。要先import,再const使用
vue框架_第50张图片

正常用法
先调用actions

ji() {
  this.$store.dispatch("jix", this.n);
},

actions再调用mutations

jix(context, value) {
    if (value%2) context.commit('JIAX',value)
},

mutations执行对应的操作

如果仅仅是简单直接的操作,没有条件判断之类的,可以直接调用mutations

jia() {
  this.$store.commit("JIAX", this.n);
},

5.3store中的其他方法

1.getters
类似于计算属性

getters: {
    bigsum(state) {
        return state.sum*10
    }
},

使用方法$store.getters.bigsum

5.4vuex映射方法

1.mapstate,mapgetters
用来映射数据生成计算属性
①常规计算属性写法

  computed: {
    sum() {
      return this.$store.state.sum;
    },
    ys() {
      return this.$store.state.ys;
    },
    bh() {
      return this.$store.state.bh;
    },
    bigsum() {
      return this.$store.getters.bigsum;
    },
  },

②使用映射的写法-有两种对象写法和数组写法
先引入

import { mapState, mapGetters } from "vuex";

对象写法

  computed: {
    ...mapState({ sum: "sum", ys: "ys", bh: "bh" }),
    ...mapGetters({ bigsum: "bigsum" }),
  },

数组写法(适用于组件属性名和state的属性名一致的场景)

  computed: {
    ...mapState(["sum", "ys", "bh"]),
    ...mapGetters(["bigsum"]),
  },

2.mapactions,mapmutations
①正常的调用actions和mutations方法的方式

  methods: {
    jia() {
      this.$store.commit("JIAX", this.n);
    },
    jian() {
      this.$store.commit("JIANX", this.n);
    },
    ji() {
      this.$store.dispatch("jix", this.n);
    },
    djia() {
      this.$store.dispatch("djiax", this.n);
    },
  },

②引入

import { mapState, mapGetters,mapActions,mapMutations } from "vuex";

③写法-也是有对象和数组写法两种
这里只写了对象写法,如果名字一样用数组写法

methods: {
    ...mapMutations({ jia: "JIAX", jian: "JIANX" }),
    ...mapActions({ ji: "jix", djia: "djiax" }),
  },

**注意:**使用map生成的话,调用方法的时候要记得传参

<button @click="jia(n)">+</button>

5.5vuex模块化

1.vuex组件化编写
①把不同功能的属性和方法写在一个单独的js文件中,
在这里插入图片描述
②把模块默认暴露出去,注意要写namespaced,后边组件才能正常映射属性和方法

export default {
    namespaced:true,
        // 数据仓库
        state:{
            sum: 0,
            ys: '原神',
            bh:'崩坏三'
        },
    
        // 获取数据,类似于计算属性,逻辑复杂且还想复用就用getters
        getters: {
            bigsum(state) {
                return state.sum*10
            }
        },
        // 异步方法
        actions: {
            // context存放着几个可能要用的方法,可以理解为一个迷你版的store
            jix(context, value) {
                if (value%2) context.commit('JIAX',value)
            },
            djiax(context, value) {
                setTimeout(() => {
                    context.commit('JIAX',value)
                }, 1000);
            }
        },
            
        // 更改state的方法
        mutations: {
            // 第一个参数就是state
            JIAX(state,value) {
                state.sum+=value
            },
            JIANX(state,value) {
                state.sum-=value
            },
    
        },
}

③index.js导入模块并注册

import { createStore } from 'vuex'
import count from './count'
import coushude from './coushude'
export default createStore({
   
    // 分包
    modules: {
        count,
        coushude
    }
})

④组件的使用,导入特定模块的属性和方法

methods: {
    ...mapMutations("count", { jia: "JIAX", jian: "JIANX" }),
    ...mapActions("count", { ji: "jix", djia: "djiax" }),
  },
  computed: {
    ...mapState("count", ["sum", "ys", "bh"]),
    ...mapGetters("count", ["bigsum"]),
  },

6.vue-router

6.1路由简述

一个路由就是一组key-value映射关系,key为路径,value可能是组件或者函数
spi就是一个单页面应用
vue-router是一个vue插件

6.2vue-router的使用

和vuex类似
1.安装
npm i vue-router
2.创建router
src/router/index.js
在此处写router信息
然后引入组件,编写路径

import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../components/AboutV.vue'
import HomeV from '../components/HomeV.vue'

export default createRouter({
    history: createWebHistory(),
    routes: [
        {
            path: '/about',
            component:AboutV
        },
        {
            path: '/home',
            component:HomeV
        },
    ],
    
})

3.router引入

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
createApp(App).use(router).mount('#app')

4.使用

<template>
  <div>
    <p>
      <router-link to="/about">about</router-link>
      <router-link to="/home">home</router-link>
    </p>
    <router-view></router-view>
  </div>
</template>

注意:
①如果要让路由组件和静态组件区分开,可以建立一个和components同级的pages文件夹,来放路由组件
②隐藏的的路由页面实际是被销毁了的,可以用beforedestroy钩子测试,需要的时候再挂载
③每个组件都有一个 r o u t e , 储存着自己的路由信息,整个应用只有一个 route,储存着自己的路由信息,整个应用只有一个 route,储存着自己的路由信息,整个应用只有一个router属性

6.3嵌套路由

1.引入组件,编写路由
把路由写在children数组里,
注意:一级路由path要带/,子级不用带

import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../pages/AboutV.vue'
import HomeV from '../pages/HomeV.vue'
import OneV from '../pages/OneV.vue'
import TwoV from '../pages/TwoV.vue'

export default createRouter({
    history: createWebHistory(),
    routes: [
        {
            path: '/about',
            component:AboutV
        },
        {
            path: '/home',
            component: HomeV,
            children: [
                {
                    path: 'one',
                    component:OneV
                },
                {
                    path: 'two',
                    component:TwoV
                }
            ]
        },
    ],
    
})

2.使用
和一级路由类似,不同点在于to后的路径要一二级路由都写

<template>
  <div>
    <h2>这是home组件</h2>
    <router-link to="/home/one">one</router-link>
    <router-link to="/home/two">two</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "HomeV",
};
</script>

6.4路由传参(query参数)

vue框架_第51张图片

6.5路由命名

可以简化跳转操作
1.命名
vue框架_第52张图片
2.简化跳转,可以直接在to后边写名字完成跳转,不用写一长串路径
vue框架_第53张图片

6.6路由传参(params参数)

1.配置占位符
vue框架_第54张图片
2.传递参数
如果用对象写法,必须用name,不能用path
vue框架_第55张图片
3.接收参数
在这里插入图片描述

6.7路由传参(props参数)

有三种写法,如下
接受的话和以前的props一样,正常接收即可
vue框架_第56张图片

6.8router-link的replace属性

vue框架_第57张图片
push的话是留下每一次点击的痕迹,即便是12121212121重复切换,回退也是重复切换着回去
replace则是替换掉同级路由的痕迹,直接回上一层

6.9编程式路由

不借助router-link的路由方式
主要api有push,replace,foward,back,go(括号内参数代表动几下)

vue框架_第58张图片

6.10缓存路由组件

正常情况下,切换其他组件后,该组件就会被销毁
而使用缓存,在展示组件的router-view处内侧放置keepalive标签,就能实现组件缓存不销毁
include作用是指定缓存的组件,只有指定的才会缓存,其他的不会
指定的名字用组件名
如下是vue3的方式,和vue2不一样

 <router-view v-slot="{ Component }">
      <keep-alive include="TwoV">
        <component :is="Component" />
      </keep-alive>
    </router-view>

6.11两个新的生命周期钩子

activated激活前
deactivated失活前

6.12路由守卫

用来限制路由通过的方式
有全局守卫,独享守卫,组件内守卫三种

6.12.1全局守卫

1.全局前置守卫-在跳转之前调用
from:从那来
to:到哪去
next():执行跳转动作
没有next()或者next(false)代表拒绝跳转

import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../pages/AboutV.vue'
import HomeV from '../pages/HomeV.vue'
import OneV from '../pages/OneV.vue'
import TwoV from '../pages/TwoV.vue'

const router=createRouter({
    history: createWebHistory(),
    routes: [
        {
            path: '/about',
            component:AboutV
        },
        {
            path: '/home',
            component: HomeV,
            children: [
                {
                    path: 'one',
                    component:OneV
                },
                {
                    path: 'two',
                    component:TwoV
                }
            ]
        },
    ],
    
})

router.beforeEach((to,from,next) => {
    if (to.fullPath=='/home/two'||to.fullPath=='/home') {
        next()
    } else {
        alert('丑拒')
    }
    

})
export default router

用其他信息做条件判断过于复杂,可以给它配置meta中的属性,然后来判断,这里只是个简单例子
比如可以用来做鉴权,也就是只有有这个属性的路由才会进行条件判断
vue框架_第59张图片
2.全局后置守卫-在跳转之前调用
马后炮,可用于修改页面标题等

router.afterEach((to,from) => {
    document.title=to.meta.title
})

6.12.2独享路由守卫

配置在具体路由中
当要跳转该路由时触发
注意:
①是beforeEnter,不是beforeEach
②独享是没有后置的,但是可以搭配全局后置使用

 {
                    path: 'two',
                    component: TwoV,
                    meta: {
                        isauth:true
                    },
                    beforeEnter:(to,from,next)=> {
                        console.log(to);
                        next()
                    }
                }

6.12.3组件内路由守卫

写在组件内,和mounted,methods等同级
注意名字,这俩不是前置和后置
而是进入组件前和出了组件后
vue框架_第60张图片

6.13路由器工作的两种模式

vue框架_第61张图片
现在一般用history模式
history模式的404问题要在后端解决,可以通过npm的一个插件connect…或者nginx解决

6.14项目打包部署

1.vue项目打包
使用npm run build打包成dist文件

2.搭建服务器
这里搭建的是简单服务器

const express = require("express")
var history = require('connect-history-api-fallback');
const app = express()
app.use(history())
app.use((request,response,next) => {
    console.log("有人请求1了");
    next()
})
app.use(express.static(__dirname+'/static'))
app.get('/students', (request,response) => {
    const students = ["这是数据"]
    response.send(students)
})

app.listen(5005, (err) => {
    if(!err) console.log("启动成功");
})

3.解决404问题,导入插件并使用
vue框架_第62张图片

7.vue UI组件库

vue框架_第63张图片
按需选择ui组件
一般不全部引入,太大,按照教程进行部分引入即可

8.vue3

8.1vue3简介

于2020年9.18发布
vue框架_第64张图片
vue框架_第65张图片

8.2创建vue3工程

有vecli和vite两种方式
更多还是用vuecli
vue3组件模板中可以没有根标签,也就是说一个template中可以放很多标签

8.3常用compositionAPI

compositionAPI翻译过来就是组合式api

8.3.1setup

vue框架_第66张图片

8.3.2ref函数

原来学到过一个ref属性,用来打标签获取dom元素
这里的ref是一个函数,用于定义响应式数据
生成的对象称为引用实例对象
vue框架_第67张图片

8.3.3reactive函数

vue框架_第68张图片

8.3.4vue2和vue3的响应式原理

在这里插入图片描述
vue框架_第69张图片

8.3.5setup的两个注意点

vue框架_第70张图片
1.props
就是外部传递的数据,props参数就是该组件接收到的props数据,如果传了没接收,props就是空对象

<script>
import { reactive } from "vue";
export default {
  name: "VueT",
  props: ["msg", "smg"],
  setup(props) {
    console.log("我先");
    console.log(props);
    const data = reactive({
      a: 1,
      b: 2,
      ahh: {
        c: 3,
        d: 4,
      },
    });
    function change() {
      data.ahh.c = 999;
      console.log(data);
    }
    return {
      data,
      change,
    };
  },
  beforeCreate() {
    console.log("wodier");
  },
};
</script>

在这里插入图片描述
2.context
vue框架_第71张图片
注意:在vue3中,传递自定义事件时,要用emits接收才能用,和props类似

8.3.6vue3计算属性

和vue2基本一致,
不过vue3用什么就得导入什么

vue框架_第72张图片

<template>
  <div>
    <input type="text" v-model="data.xing" />
    <input type="text" v-model="data.ming" />
    <h2>{{ data.fullname }}</h2>
    <input type="text" v-model="data.fullname" />
  </div>
</template>

<script>
import { reactive, computed } from "vue";
export default {
  name: "VueT",
  props: ["msg"],
  setup() {
    const data = reactive({
      xing: "张",
      ming: "三",
    });
    // 简单写法
    // data.fullname = computed(() => {
    //   return data.xing + "-" + data.ming;
    // });
    // 完整写法
    data.fullname = computed({
      get() {
        return data.xing + "-" + data.ming;
      },
      set(value) {
        const na = value.split("-");
        data.xing = na[0];
        data.ming = na[1];
      },
    });
    return {
      data,
    };
  },
};
</script>

8.3.7vue3监视属性watch

注意:
①watch监视的是变量而不是具体的值,比如a=ref(0),监视的是a变量而不是a.value具体的值0
分多种情况
1.监视ref定义的响应式数据

<script>
import { ref, reactive, watch } from "vue";
export default {
  name: "WatchV",
  setup() {
    let a = ref("奥托");
    let b = ref(500);
    const data = reactive({
      c: 8,
      d: 9,
      e: {
        f: {
          g: 10,
        },
      },
    });
    watch(a, (newvalue, oldvalue) => {
      console.log("a发生了变化", newvalue, oldvalue);
    });
    return {
      a,
      b,
      data,
    };
  },
};
</script>

2.监视ref定义的多个响应式数据
采用数组包裹的方式

<script>
import { ref, reactive, watch } from "vue";
export default {
  name: "WatchV",
  setup() {
    let a = ref("奥托");
    let b = ref(500);
    const data = reactive({
      c: 8,
      d: 9,
      e: {
        f: {
          g: 10,
        },
      },
    });
    watch([a, b], (newvalue, oldvalue) => {
      console.log("a发生了变化", newvalue, oldvalue);
    });
    return {
      a,
      b,
      data,
    };
  },
};
</script>

3.监视reactive定义的响应式数据
有两个注意点
①无法正确获取oldvalue,获取到的oldvalue和newvalue一样
②deep:true,即深度监视强制开启,关不掉

<script>
import { ref, reactive, watch } from "vue";
export default {
  name: "WatchV",
  setup() {
    let a = ref("奥托");
    let b = ref(500);
    const data = reactive({
      c: 8,
      d: 9,
      e: {
        f: {
          g: 10,
        },
      },
    });
    watch(data, (newvalue, oldvalue) => {
      console.log("a发生了变化", newvalue, oldvalue);
    },
     { immediate: true, deep: false });//false无效
    return {
      a,
      b,
      data,
    };
  },
};
</script>

4.监视reactive定义的响应式数据的一个属性
①要用箭头函数返回值输出属性才能用,不能直接data.c
②多个属性的话用数组包裹多个箭头函数即可
③属性的话可以正确监视到oldvalue
④如果属性是一个对象,要想监视则要手动开启深度监视

<script>
import { ref, reactive, watch } from "vue";
export default {
  name: "WatchV",
  setup() {
    let a = ref("奥托");
    let b = ref(500);
    const data = reactive({
      c: 8,
      d: 9,
      e: {
        f: {
          g: 10,
        },
      },
    });
    watch(
      () => data.c,
      (newvalue, oldvalue) => {
        console.log("a发生了变化", newvalue, oldvalue);
      }
    );
    return {
      a,
      b,
      data,
    };
  },
};
</script>

8.3.8vue3监视属性watchEffect

用来监视指定属性
vue框架_第73张图片

8.3.9vue3生命周期钩子

①和vue2大致一样,不同的在于最后两个不是destory而是mounted
②有两种写法,一种是和vue2一样的配置项写法,一种是放在组合式api里,
③在setup里要注意名字,下图右面那样写,记得要import
④create那俩无法写在setup里,setup功能就直接代表他俩了
⑤如果要在里面写逻辑,就用setup
在这里插入图片描述
vue框架_第74张图片

8.3.10自定义hook函数

类似于mixin,封装一系列组合api,实现复用,谁用谁引
创建hooks文件夹,和components同级,里面放自己的js文件,默认暴露一个函数,函数内是各种数据,函数,钩子
哪个组件用哪个就引入并接受

8.3.11toRef和toRefs

vue框架_第75张图片
vue框架_第76张图片
vue框架_第77张图片
把对象中的属性单独拆解出来,且为ref对象,并能够实现响应式,c变了,data里的c也会变

vue框架_第78张图片
torefs实现批量拆解,不过只能拆对象的第一层

8.4其他compositionAPI

8.4.1shallowref和shallowreactive

vue框架_第79张图片

8.4.2readonly和shallowreadonly

把一个响应式数据变成只读数据
shallow那个只变第一层,如果是个深层对象结构,那么就会第一层只读,深层还是响应式

vue框架_第80张图片

8.4.3toraw和markrow

toraw可以理解为reactive的逆过程
markrow适用于添加属性时用,
比如一个响应式数据要添加一个对象属性,正常添加后,该属性也会变成响应式,然而不想它变成响应式,那就先做markrow操作再添加
vue框架_第81张图片

8.4.4customref

用于自定义ref
ref相当于精装修房
customref相当于毛坯房,要自定义一些东西,也可以自定义一些特别的效果,比如下面的实现防抖
vue框架_第82张图片

8.4.5provide与inject

适用于祖孙传递
父子继续用props就行
vue框架_第83张图片

8.4.6响应式数据类型判断

vue框架_第84张图片

8.5compositionAPI的优势

同一个功能放在同一个就是、模块,更清晰

8.6新的组件

vue框架_第85张图片移动位置那里可以写html,body,可以写#xxx,到对应id处
vue框架_第86张图片

8.7其他

vue框架_第87张图片
vue框架_第88张图片

8.8vue3写法

vue3用什么就得import什么才能用

import { reactive } from "vue";

1.数据和方法

<script>
import { reactive } from "vue";
export default {
  name: "VueT",
  setup() {
    const data = reactive({
      a: 1,
      b: 2,
      ahh: {
        c: 3,
        d: 4,
      },
    });
    function change() {
      console.log(data.a);
    }
    return {
      data,
      change,
    };
  },
};
</script>

你可能感兴趣的:(前端,javascript,vue.js)