Vue基础

Vue基础

day1

Vue的现状

最新版本:

Vue 3.0

1、核心代码完全重构(TypeScript)

2、速度更快

3、体积更小

vue的基本使用方法

1.引入vue.js
<script src="./vue.js"></script>
2.定义模板
<div id="app"></div>
3.vue初始化
const app = new Vue({
    // 告诉我Vue生效位置,给一个dom id值,或者class
    //el 挂载点
    el:'#app',
    // data:数据对象,用于给模板进行渲染
    data:{
        //数据
    }
})
小结:

1、el给vue实例的挂载点,挂载点外的不归vue管

2、el 可以使任何选择器,id class 标签都可以

Vue data属性接收不同的类型和模板读取

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id='app'>
        <p>字符串: {{ message }}</p>
        <p>数值类型:{{ num }}</p>
        <p>布尔类型:{{ isOk }}</p>
        <p>对象类型:{{ student }}  {{student.name}} {{student['age']}}</p>
        <p>数组类型:{{ hobby }} {{ hobby[0] }}</p>
    </div>
</body>
<script>
    // data定义不同的数据类型:string, number,boolean,对象,数组
    const app = new Vue({
        el: '#app',
        data: {
            message:'简单字符串',
            num: 20,
            isOk: true,
            student: { name: 'tom', age: 18 },
            hobby: ['篮球', '足球']
        }
    })
</script>
</html>
小结:

data接收任意的js类型数据,模板读取方法和js读取是一样的。

v-text标签

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="app">
        <div>我的信息是:{{message}}</div>
        <!-- v-text会直接覆盖原有的内容,v-text等号后面直接接收data下的值 -->
        <div v-text="message">我的信息是:</div>
        <!-- 如果v-text需要拼接字符,可以用这个方式 -->
        <div v-text="'我的信息是:' + message">我的信息是:</div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '黑马57前端'
        }
    })
</script>

</html>
小结

1.v-text会直接覆盖原有的内容,v-text等号后面直接接收data下的值

2.如果v-text需要拼接字符,可以用这个方式

 <div v-text="'我的信息是:' + message">我的信息是:</div>

v-html标签

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <!-- v-html标签:用于解析html元素的 -->
    <div id="app">
        <div>{{message}}</div>
        <div v-html="message"></div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '<h1>少林功夫好耶</h1><h2>我系铁头功</h2>'
        }
    })
</script>

</html>
小结

1.html可以解析html结构

v-bind语法(操作标准属性属性值)

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
    <style>
        .box {
            width:100px;
            height: 100px;
            background-color: red;
        }
        .yellowBox {
            width:100px;
            height: 100px;
            background-color: yellow; 
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="box"></div>
        <!-- 如果要给属性设置值,这是不允许的 -->
        <div class="{{myClass}}"></div>
        <div :class="myYellow"></div>
        <div v-bind:class="myClass"></div>
        <!-- 显示logo图片 -->
        <img :src="logo"/>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            myClass: 'box',
            myYellow: 'yellowBox',
            logo: 'https://cn.vuejs.org/images/logo.png'
        }
    })
</script>

</html>
小结

1、用于html属性的赋值

2、v-bind还可以简写为:

<div v-bind:class="myClass"></div>
        <!-- 显示logo图片 -->
<img :src="logo"/>

vue表达式

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<!-- 表达式:三目运算,加法,减法,&&,|| -->
<body>
    <div id="app">
        <div>三目运算符:{{ age >= 18 ? '成年人' : '精神小伙'}}</div>
        <div>加法运算:{{ age + 1 }}</div>
        <div>减法运算:{{ age - 1 }}</div>
        <div v-bind:id="'item-' + id"></div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            age: 18,
            id: 1,
        }
    })
</script>

</html>
小结

1、Vue的模板语法支持常见的表达式,例如三目运算符、加法、减法、和运算、或运算

vue中的循环v-for

语法:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<!-- v-for语法:用于循环数组 -->
<!-- 第一种写法 -->
<!-- <div v-for="别名 in 目标数组"></div> -->
<!-- 第二种写法 -->
<!-- <div v-for="(别名, 索引变量) in 目标数组"></div> -->


<!-- key值问题,Vue为了优化列表渲染需要依赖的一个值,你可以不提供给他 -->
<!-- 如果不提供,会提示警告,一般情况下都需要一个key值 -->
<body>
    <div id="app">
        <!-- 循环数组 -->
        <div>我的爱好是</div>
        <p v-for="(item, index) in hobby" :key="index">
            {{item}}
        </p>

        <!-- 循环数组,读取对象 -->
        <div>学生信息</div>
        <p v-for="(stu, idx) in students" :key="stu.id">{{idx + 1}}条数据:我的名字叫{{stu.name}},年龄 {{stu.age}}
        </p>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            hobby: [ '篮球', '足球', '羽毛球' ],
            students: [ { id: 10001 ,name: 'tom', age: 18 }, { id: 1002, name: 'jake', age: 20 } ]
        }
    })
</script>

</html>
v-for中的key值

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XI6dUVnV-1609341216699)(Vue.assets/image-20201109154807423.png)]

v-for对象循环
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- 循环对象:v-for="(属性值,属性key,索引) in 对象" -->
    <div id="app">
        <p v-for="(item, key, index) in student">
            对象的属性为:{{key}} value值为:{{item}} 索引值:{{index}}
        </p>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            student: {
                name: 'tom',
                age: 18
            }
        }
    })
</script>

</html>

在这里插入图片描述

小结

:对象循环也是使用v-for语法,但是他们的值有点不一样

v-for="(属性值,属性key,索引) in 对象"
for循环的问题

在这里插入图片描述

v-if的语法

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>判断语法</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- v-if="布尔值" -->
    <div id="app">
        <div v-if="isOK">这是isOk为true的时候显示</div>

        <!-- 字符串作为v-if条件 -->
        <!-- 空串表示false值,非空串表示true值 -->
         <div v-if="test">会显示test的内容吗?</div>

         <!-- undefined值,也表示false -->
         <div v-if="name">会显示undefined吗</div>

         <!-- null值 -->
         <div v-if="gender">能显示gender吗</div>

         <!-- 数值类型, 0表示false, 其他表示true -->
         <div v-if="num">是否显示num</div>

         <div v-if="age > 18">成年小伙</div>
         <div v-else>精神小伙</div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            isOK: true,
            test: 'test',
            name: undefined,
            gender: null,
            num: 1,
            age: 18
        }
    })
</script>

</html>
小结

1、语法: v-if="条件"

 <div v-if="name">会显示undefined吗</div>

2、条件可以是任意的js表示真或者假的值

3、还可以增加v-else语句和v-else-if语句

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

v-show的语法

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-show语法</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- v-show="表示真值或者假值" -->
    <!-- v-show如果为false的时候,实际是给元素增加display:none样式 -->
    <!-- v-if 如果为false,直接把元素从dom移除 -->

    <!-- 使用场景区别 -->
    <!-- 当元素频繁的切换可见状态,v-show -->
    <!-- 否则,可以用v-if -->
    <div id="app">
        <div v-show="isOK">v-show语法控制元素</div>
        <div v-if="isOK">v-if语法控制的元素</div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            isOK: false
        }
    })
</script>

</html>
小结

1.v-show如果为false的时候,实际是给元素增加display:none样式, v-if 如果为false,直接把元素从dom移除

2.使用场景:当元素频繁的切换可见状态,v-show,否则,可以用v-if, 因为v-if为真要重新渲染Dom结构,造成性能浪费

v-model实现radio单选框

v-model

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定,指令会帮你自动把输入的值更新到数据中。

message的值也会自动显示给绑定表单的元素上,假如value的初始值跟message的初始值不一样,通过v-madel绑定message的值会覆盖掉

value上的值

在这里插入图片描述

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-model语法</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- 如果是radio标签,通过v-model绑定同一个值,他们之间会自动实现互斥的关系 -->
    <!-- 如果需要实现数据初始化,给绑定的变量赋予初始值,初始值应该和radio的value值相等 -->
    <div id="app">
        <input type="radio" name="gender" id="" value="" v-model="gender"><input type="radio" name="gender" id="" value="" v-model="gender"><input type="radio" name="gender" id="" value="不详" v-model="gender">不详
        <div>选择的性别是:{{gender}}</div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            gender: '女'
        }
    })
</script>

</html>
小结:

1、radio的v-model属性需要绑定同一个值才能成为一组

2、如果需要实现数据初始化,给绑定的变量赋予初始值,初始值应该和radio的value值相等

v-model实现checkbox复选框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-model语法</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- value是必须的值 -->
        <input type="checkbox" v-model="hobby" value="basketball">篮球
        <input type="checkbox" v-model="hobby" value="football">足球
        <input type="checkbox" v-model="hobby" value="music">音乐
        <div>兴趣:{{hobby}}</div>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            hobby: ['basketball']
        }
    })
</script>

</html>
小结

1、checkbox必须有value值,否则会出错

input:textinput事件与change事件

input事件触发

在这里插入图片描述

change事件触发

在这里插入图片描述

day2

网站优化问题

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPvoHrqz-1609341216714)(Vue.assets/image-20201110093653510.png)]

事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- 数据驱动视图、数据模型驱动 -->
    <!-- 关注的只有数据,不需要关注视图相关代码 -->
    <div id="app">
        <div>当前的数量是 {{ counter }} </div>
        <!-- 通过 v-on:事件名 添加事件 -->
        <button v-on:click="counter++">加一</button>
        <!-- 可以用下面的两个方法绑定事件 -->
        <!-- <button v-on:click="reduce()">减一</button> -->
        <button v-on:click="reduce">减一</button>

        <!-- 给事件传递参数 -->
        <button v-on:click="sayHello('tom')">弹出问好的语句</button>

        <!-- 事件绑定的简写形式 -->
        <button @click="sayHello('tom')">简写的事件绑定</button>
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            counter: 0
        },
        // methods表示页面的方法
        methods: {
            // 第一种写法
            // reduce: function() {
            //     this.counter--;
            // }
            // 第二种,基于ES6的函数定义
            reduce() {
                this.counter--
            },
            sayHello(name) {
                alert(name + '你好呀')
            }
        }
    })
</script>
</html>
小结

1、定义的语法v-on:事件名

2、v-on:click = “方法名/表达式”

3、方法要定义在Vue对象的methods

4、方法的参数传递,可以直接通过绑定事件时传递 v-on:click="sayHello('tom')"

5、事件绑定的简写, @click="sayHello"

事件修饰符

事件修饰符就是拿来阻止默认事件,冒泡之类的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- Vue阻止默认行为 -->
        <!-- 第一种方法 -->
        <form @submit="login">
            <input type="text" name="userName">
            <button type="submit">登录</button>
        </form>

        <!-- 第二种方法 -->
        <form @submit.prevent="register">
            <input type="text" name="userName">
            <button type="submit">注册</button>
        </form>
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
        },
        methods: {
            // 第一种实现方法
            login(e) {
                console.log(e)
                e.preventDefault();
                console.log('login')
            },
            // 第二种实现方法
            register() {
                console.log('register')
            }
        }
    })
</script>
</html>

键盘修饰符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 绑定键盘事件,监听keyup事件,表示按键弹起的时候 -->
        <!-- 要监听回车键 -->
        <input type="text" @keyup.enter="userInput" v-model="userInfo">
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            userInfo: ''
        },
        methods: {
            userInput() {
                // 显示用户输入的内容
                console.log('用户按下了回车键' + this.userInfo)
            }
        }
    })
</script>
</html>
小结

键盘修饰符可以拿来监听键盘键

Vue自定义指令

<input type="text" autofocus>   但是这种ios 系统不支持
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <input type="text" id="myInput" v-focus>
        <button @click="userFocus()">聚焦</button>
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
        },
        methods: {
            // 不优雅
            userFocus() {
                document.querySelector('#myInput').focus();
            }
        },
        // 使用自定义指令
        directives: {
            // 属性名字是变化的,你需要定义成什么指令就起什么名字,v-foucs
            focus: {
                // inserted是一个钩子函数,当dom被插入到父节点的时候,会被调用
                inserted(el) {
                    // el是原生dom元素,然后调用focus进行聚焦
                    el.focus();
                }
            }
        }
    })
</script>
</html>
小结

1、指令应该定义在directives

2、指令的名字作为对象的key

3、对象的value值,定义钩子函数,例如inserted

4、在inserted函数里面获取原生dom元素,调用foucs方法

5、在dom元素,加入v-focus

在这里插入图片描述

过滤器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 使用过滤器 -->
        <!-- 使用管道符 -->
        <div>{{ name | upper }}</div>
        <div v-bind:id="name | upper"></div>
        
        <!-- 使用多个管道 -->
        <div>{{ price | toyuan | multiply}} 元</div>

        <!-- 过滤文明用语 -->
        <div>{{ message | towenming }}</div>
        
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            name: 'tom',
            price: 10000,
            message: '你西内'
        },
        methods: {

        },
        // 过滤器定义的位置
        filters: {
            upper(value) {
                return value.toUpperCase();
            },
            toyuan(value) {
                return value / 100;
            },
            // 乘10
            multiply(value) {
                return value * 10
            },
            // 把语言过滤成优雅的说法
            towenming(value) {
                return value.replace('西内', '好棒哦')
            }
        }
    })
</script>
</html>
小结

1、定义过滤器,过滤器都定义在filters对象中

2、filters对象中可以定义多个过滤器,过滤器实际上就是一个函数,函数会接收到一个值,这个值是管道前面的变量

3、使用过滤器的方法,需要用到一个管道符<div>{{ name | upper }}</div>

4、管道符就是 |

计算属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 第一种方法:模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。 -->
        <div>{{ phone.substr(0, 4) + '****' + phone.substr(7)}}</div>  
        <!-- 第二种方法 -->
        <div>{{getPhone()}}</div>
        <!-- 第三种方法 -->
        <div>使用计算属性:{{displayPhone}}</div>
        <input type="text" v-model="phone">
    </div>
</body>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            phone: '18661111234'
        },
        methods: {
            getPhone() {
                return this.phone.substr(0, 4) + '****' + this.phone.substr(7)
            }
        },
        // 计算属性
        computed: {
            displayPhone() {
                return this.phone.substr(0, 4) + '****' + this.phone.substr(7)
            }
        }

    })
</script>
</html>

小结

1、计算属性要定义在computed节点

2、计算属性调用的时候和普通方法不太一样,方法是需要方法名(),计算属性直接写上计算属性方法名就可以

3、计算属性触发重新执行的时机,计算属性内依赖的值发生改变时,会重新计算

算属性与普通方法的差异:

计算属性具有缓存的能力,当计算属性内依赖的属性没发生改变,他就不会被重新执行;但是方法调用会根据调用次数执行不同的次数

在这里插入图片描述

computed与methods的差异

computed会产生缓存机制,但如果computed属性计算中所依赖的数据发生改变,computed也会随着改变。而methods每次都会计算一次数值,浪费性能

day3

侦听属性watch

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-model="firstName">
        <input type="text" v-model="lastName">
        <div>全名:{{fullName}}</div>
    </div>
</body>
<script>
    // 使用侦听属性 watch
    const app = new Vue({
        el: '#app',
        data: {
            firstName: '',
            lastName: '',
            fullName: '',
        },
        watch: {
            // 侦听firstName属性的变化,value就是变化的值
            firstName(newVal, oldVal) {
                this.fullName = newVal + this.lastName
            },
            lastName(newVal, oldVal) {
                this.fullName = this.firstName + newVal;
            }
        }
    })
</script>
</html>

小结:

1、侦听属性是用于监听data下属性值的变化

2、侦听属性定义在watch节点

3、侦听属性方法可以得到两个参数,分别为新的值和旧的值

firstName(newVal, oldVal) {
                this.fullName = newVal + this.lastName
 },

4、如果页面上需要监听数据并且显示某个值,可以考虑计算属性,否则用侦听器

侦听属性deep属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <div>{{product.name}}</div>
        <div>价格:{{product.price}}块</div>
        <input type="text" v-model="product.amount">
    </div>
</body>
<script>
    // 使用侦听属性 watch
    const app = new Vue({
        el: '#app',
        data: {
           product: {
               name: '商品名字',
               price: 100,
               amount: 0
           }
        },
        // 监听amount变化,发送ajax请求到服务端,检查库存数量
        watch: {
            // 如果你要监听对象里的某个属性,可以用这种写法
            // 'product.amount': function(newVal) {
            //     console.log(newVal)
            // }

            // 这个写法不能监听对象的子属性
            // product(newVal) {
            //     console.log(newVal)
            // }
            product: {
                // deep表示深度监听,把对象或者数组的子元素都进行监听
                deep: true,
                // newVal得到的是监听对象
                handler(newVal, oldVal) {
                    console.log(newVal, oldVal)
                }
            }
        }
    })
</script>
</html>
小结:

1、监听对象或者数组,是没法监听子属性的变化。

2、通过deep属性设置为深度监听,才能监听对象或者数组的子属性

3、侦听处理函数,写在handler属性里

Vue的生命周期

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

小结

1.Vue的生命周期也就是这八个钩子函数组成的

网络请求一般放在什么周期?

放在createdmounted都可以,一般情况下mounted

什么生命周期才能拿到 data的数据?

created周期才能拿到

自定义组件

组件解决代码复用,js复用的函数,vue的页面复用

如何定义组件
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 使用组件 -->
        <counter></counter>

        <!-- 如果组件使用驼峰命名,使用的时候,把驼峰改为横杆 -->
        <!-- <heimaCounter></heimaCounter> -->
        <heima-counter></heima-counter>

        <xboss-counter></xboss-counter>
    </div>
</body>
<script>
    // 定义自定义全局组件
    // couter表示组件的名字
    Vue.component('counter', {
        // template表示组件模板
        template: '<div>hello component</div>'
    })

    Vue.component('heimaCounter', {
        // template表示组件模板
        template: '<div>hello heima</div>'
    })

    Vue.component('xboss-counter', {
        // template表示组件模板
        // 注意!Vue组件模板只允许有一个根元素
        template: `
        <div>
            <div>hello xboss-counter</div>
            <div>test</div>
        </div>`
    })

    const app = new Vue({
        el: '#app'
    })
</script>

</html>
小结

1、定义全局组件,可以通过Vue.component('组件名', { template })

2、组件名建议都用小写,如果是两个单词,用横杠连接,尽量不要用驼峰命名,如果用了驼峰命名,在使用的时候驼峰的大写用横杠连接。

组件传参

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>
        <blog-post title="这是第二条新闻标题" content="这是第二条新闻内容"></blog-post>
        <blog-post title="这是第三条新闻标题" content="这是第三新闻内容"></blog-post>
    </div>
</body>
<script>
    // 定义一个显示文章的组件
    // 名字叫:blog-post
    // 接收的参数:title content
    Vue.component('blog-post', {
        // 通过props对象接收传递过来的数据
        // 组件接收外部参数,用props
        props: [ 'title', 'content' ],
        // 组件内部的数据,用data定义
        data() {
            return {
                author: '蟹老板'
            }
        },
        template: `
            <div>
                <h1>{{title}}</h1>
                <p>作者:{{author}}</p>
                <h3>{{content}}</h3>
            </div>
        `
    })

    const app = new Vue({
        el: '#app',
    })
</script>
</html>
小结

1、组件通过props属性接收外部参数

2、给组件传递参数的写法<blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>

组件验证参数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <blog-post title="这是新闻标题" content="这是新闻内容"></blog-post>
        <blog-post title="这是第二条新闻标题" content="这是第二条新闻内容"></blog-post>
        <blog-post title="第三条新闻标题" :content="num"></blog-post>
    </div>
</body>
<script>
    // 定义一个显示文章的组件
    // 名字叫:blog-post
    // 接收的参数:title content
    Vue.component('blog-post', {
        // 通过props对象接收传递过来的数据
        // 组件接收外部参数,用props
        // props: [ 'title', 'content' ],
        // 验证props属性
        props: {
            // 对象的key值就是参数的名字,value值验证规则
            title: {
                // 验证数据不能为空,如果传递空值,会提示警告
                required: true,
            },
            // 验证cotnent必须为String类型
            content:String
            
                
        },
        // 组件内部的数据,用data定义
        data() {
            return {
                author: '蟹老板'
            }
        },
        template: `
            <div>
                <h1>{{title}}</h1>
                <p>作者:{{author}}</p>
                <h3>{{content}}</h3>
            </div>
        `
    })

    const app = new Vue({
        el: '#app',
        data() {
            return {
                num: 1
            }
        }
    })
</script>
</html>

小结:

1、验证参数可以通过props等于一个对象

required是否必填

type 数据传入类型,可以设置为任何的JS基础类型

default 数据默认值

props: {
    // 对象的key值就是参数的名字,value值验证规则
    title: {
        // 验证数据不能为空,如果传递空值,会提示警告
        required: true,
    },
        content: {
            // 验证cotnent必须为String类型
            type: String
        }
    },

day4

父子组件概念

父更早创建的,子在父里面

blog-post是app实例的子组件,other是app的孙组件

<div id="app">
    <blog-post v-for="(item, index) in newsList" :news="item"></blog-post>
    <!--父组件-->
    <blog-post v-for="(item, index) in newsList" :news="item">
        <!--子组件-->
        <other></other>
    </blog-post>
</div>

父子组件之间通讯

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 父组件接收子组件事件,然后做相应的逻辑 -->
        <blog-post @hide="childHide" v-for="(item, index) in newsList" :index="index" :news="item"></blog-post>
    </div>
</body>
<script>
    // 定义一个显示文章的组件
    // 名字叫:blog-post
    // 接收的参数:title content
    Vue.component('blog-post', {
        // 通过props对象接收传递过来的数据
        // 组件接收外部参数,用props
        props: [ 'news', 'index' ],
        template: `
            <div>
                <h1>{{news.title}}</h1>
                <p>作者:{{news.author}}</p>
                <h3>{{news.content}}</h3>
                <button @click="hideNews">屏蔽当前信息</button>
            </div>
        `,
        methods: {
            hideNews() {
                // 如何通知父组件?
                // 发送事件及传递数值给父组件
                // 通过$emit('自定义事件名')
                this.$emit('hide', this.index)
            }
        }
    })

    const app = new Vue({
        el: '#app',
        data() {
            return {
                newsList: [
                    { title: '新闻标题1', content: '新闻内容', author: '蟹老板' },
                    { title: '新闻标题2', content: '新闻内容', author: '蟹老板' },
                    { title: '新闻标题3', content: '新闻内容', author: '蟹老板' },
                ]
            }
        },
        methods: {
            // 接收到子组件事件后,处理函数
            childHide(index) {
                // 直接把newsList删除掉相应的元素
                this.newsList.splice(index, 1)
            }
        }
    })
</script>
</html>

小结:

1、子组件通过this.$emit(‘事件名’, '参数')发送事件通知父组件

2、父组件通过v-on:子组件事件名="父组件处理函数"

兄弟组件之间通讯

在这里插入图片描述

在这里插入图片描述

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="app">
        <aiqi1 @yy="aiqi"></aiqi1>
        <!--利用v-bind向组件模板传入content-->
        <aiqi2 :title="content"></aiqi2>
    </div>
</body>
<script>
    Vue.component('aiqi1', {
        template: `<div>
			//使用emit向组件aiqi1发送参数zyf
            <input type="text" v-model="zyf" @keyup="$emit('yy',zyf)" >
            </div>`,
        data() {
            return {
                zyf: '',
            }
        }
    })
    Vue.component('aiqi2', {
        props: ['title'],
        template: `<div>{{title}}</div>`
    })
    const app = new Vue({

        el: "#app",
        data() {
            return {
                content: '',
            }
        },
        methods: {
            aiqi(zyf) {
                this.content = zyf;
            }
        },
    });
</script>

</html>

小结:

1、子组件通过$emit传递数据给父组件

2、父组件保存子组件传递过来的数据

3、父组件把数据通过props传递给其他兄弟组件

局部组件和全局组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        {{msg}}
        <blog></blog>
    </div>

    <div id='app2'>
        {{msg}}
        <blog></blog>
        <comment></comment>
    </div>
</body>
<script>
    // 全局组件,会在所有vue的实例都生效
    Vue.component('blog', {
        template: '<div>myblog</div>'
    })


    // 第一个vue实例
    const app = new Vue({
        el: '#app',
        data() {
            return {
                msg: 'app'
            }
        }
    })

    // 第二个实例
    const app2 = new Vue({
        el: '#app2',
        data() {
            return {
                msg: 'app2'
            }
        },
        // 局部组件,用于声明当前实例有什么组件
        components: {
            comment: { template: '<div>comment组件</div>' }
        }
    })

</script>
</html>

1、全局组件通过Vue.component方法定义

2、全局组件可以给任意的实例调用

3、局部组件定义在实例的components节点

4、定义方法

        components: {
            comment: { template: '<div>comment组件</div>' }
        }

Vue路由

单页应用(SPA:single page application):把所有的页面加载到同一个html页面,然后通过切换元素的显示和隐藏状态,实现页面的流畅切换效果。

单页应用的优势:切换流畅,使用体验比较好

单页应用劣势:首次加载较慢,一般单页应用多用于后台管理系统,或者一些追求体验移动应用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 第一步:引入vue和vue-router -->
    <script src="./vue.js"></script>
    <script src="./vue-router.js"></script>
</head>
<body>
    <div id="app">
        <!-- <a href="#/login">登录</a>
        <a href="#/register">注册</a> -->
        <router-link to="/login">登录</router-link>
        <router-link to="/register">注册</router-link>
        <!-- 用于显示路由页面元素 -->
        <router-view></router-view>
    </div>
</body>

<script>
    // 定义页面组件
    const index = {
        template: `<div>首页</div>`
    }
    const register = {
        template: `
        <div>
            <div>注册页面</div>
            <label for="username">用户名:</label><br/>
            <input type="text" name="username" id="username"/><br/>
            <label for="password">密码:</label><br/>
            <input type="password" name="password" id="password"/><br/>
            <button>注册</button><br/>
        </div>
        `
    }

    const login = {
        template: `
        <div>
            <div>登录页面</div>
            <label for="username">用户名:</label><br/>
            <input type="text" name="username" id="username"/><br/>
            <label for="password">密码:</label><br/>
            <input type="password" name="password" id="password"/><br/>
            <button>登录</button>
        </div>
        `
    }

    // 定义路由配置信息,routes
    const routes = [
        { path: '/', component: index },
        { path: '/login', component: login },
        { path: '/register', component: register },
    ]

    // 创建VueRouter实例,传递路由配置信息
    const router = new VueRouter({
        routes
    })

    // 路由实例传递给Vue
    const app = new Vue({
        el: '#app',
        router
    })

</script>
</html>

小结:

1、编写页面组件

2、声明路由配置信息

path: 访问的路径,component 显示的组件

const routes = [
    { path: '/', component: index },
    { path: '/login', component: login },
    { path: '/register', component: register },
]

3、实例化组件

    const router = new VueRouter({
        routes
    })

4、把路由实例传递给Vue实例

    const app = new Vue({
        el: '#app',
        router
    })

3、用于显示页面

4、用于链接跳转

哈希(hash)路由

Vue是基于哈希路由实现页面跳转的。

window.location.hash

Vue路由参数传递

1、路由配置文件加入参数名字

参数是以冒号为开始,冒号后面表示参数名字

const routes = [
    { path: '/', component: index },
    { path: '/login', component: login },
    // 注册页面接收一个参数,叫source表示来源
    // 定义路由参数写法 /register/:参数名字
    { path: '/register/:source', component: register },
]

2、给页面传递参数

<router-link to="/register/微信">注册</router-link>

3、在目标页面获取参数

this.$route表示当前页面路由对象

this.$route.params表示页面参数对象

mounted() {
    // dom渲染完毕的生命周期钩子函数
    console.log(this.$route.params.source)
}

监听路由参数的动态变化

通过watch特性监听$route对象

watch: {
    // 通过watch监听路由对象,实现参数变化监听
    // to 表示目标页面路由对象
    // from 表示从哪个页面过来的路由对象
    $route(to, from) {
    console.log(to);
    console.log(from)
    }
}

404找不到页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 第一步:引入vue和vue-router -->
    <script src="./vue.js"></script>
    <script src="./vue-router.js"></script>
</head>
<body>
    <div id="app">
        <!-- <a href="#/login">登录</a>
        <a href="#/register">注册</a> -->
        <router-link to="/login">登录</router-link>
        <router-link to="/register">注册</router-link>
        <!-- 用于显示路由页面元素 -->
        <router-view></router-view>
    </div>
</body>

<script>
    // 定义页面组件
    const index = {
        template: `<div>首页</div>`
    }
    const register = {
        template: `
        <div>
            <div>注册页面</div>
            <label for="username">用户名:</label><br/>
            <input type="text" name="username" id="username"/><br/>
            <label for="password">密码:</label><br/>
            <input type="password" name="password" id="password"/><br/>
            <button>注册</button><br/>
        </div>
        `
    }

    const login = {
        template: `
        <div>
            <div>登录页面</div>
            <label for="username">用户名:</label><br/>
            <input type="text" name="username" id="username"/><br/>
            <label for="password">密码:</label><br/>
            <input type="password" name="password" id="password"/><br/>
            <button>登录</button>
        </div>
        `
    }

    const NotFound = {
        template: '<div>页面找不到</div>'
    }

    // 定义路由配置信息,routes
    const routes = [
        { path: '/', component: index },
        { path: '/login', component: login },
        { path: '/register', component: register },
        //通过*表示路径找不到
        { path: '*', component: NotFound }
    ]

    // 创建VueRouter实例,传递路由配置信息
    const router = new VueRouter({
        routes
    })

    // 路由实例传递给Vue
    const app = new Vue({
        el: '#app',
        router
    })

</script>
</html>

day5

编程式路由

以前是通过router-link进行页面跳转,但是有些时候,是希望通过在执行逻辑的时候调用js进行页面跳转的。以前,是通过window.location.href = "地址"

router.push 在原来路由基础上,跳转到另外一个路由

第一种:(最常用方法)

router.push('跳转路径')

第二种:(相对少用)

router.push({ name: '路由名字', params: { source: '123' } })

router.replace 替换路由,用该方法会替换掉上一个路由访问历史

router.replace('路由路径')

<router-link to="路由路径" replace></router-link>

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
    <script src="./vue-router.js"></script>
</head>

<body>
    <div id="app">
        <!-- 通过页面元素跳转 -->
        <router-link to="/login">去登录页</router-link>
        <a href="#/register">跳转到注册-使用a标签</a>
        <!-- 编程式路由 -->
        <div @click="jumpToRegister">跳转到注册</div>
        <div style="margin: 50px;border: 5px solid red">
            <router-view></router-view>
        </div>
    </div>
</body>
<script>
    const Login = {
        template: '<div>这是一个登录页面</div>'
    }
    const Register = {
        template: '<div>这是一个注册页面</div>'
    }
    // 初始化路由
    // 1、路由配置
    const routes = [
        { path: '/login', component: Login },
        { path: '/register/:source', component: Register, name: 'register' }
    ]
    // 2、实例化路由
    const router = new VueRouter({
        routes
    })
    // 初始化Vue
    const app = new Vue({
        el: '#app',
        router,
        methods: {
            jumpToRegister() {
                // 使用原生的跳转,也是可以,实际上,只要能操作到url的变化,都可以跳转
                // window.location.href = '#/register'
                // 第一种使用编程式跳转的方法
                // router.push('/register')
                // 第一种方法,传递参数
                // router.push('/register/123')
                // 第二种(比较少用),注意,只能通过name进行跳转,params传递参数
                // router.push({ name: 'register', params: { source: '123' } })
                //第三种替换式跳转,就是替换跳转前的页面,跳转后想返回上页的结果,跳转的是上上页
                //router.replace('/replace/123456')
            }
        }
    })
</script>

</html>

小结

// 使用原生的跳转,也是可以,实际上,只要能操作到url的变化,都可以跳转
// window.location.href = ‘#/register’
// 第一种使用编程式跳转的方法
// router.push(’/register’)
// 第一种方法,传递参数
// router.push(’/register/123’)
// 第二种(比较少用),注意,只能通过name进行跳转,params传递参数
// router.push({ name: ‘register’, params: { source: ‘123’ } })
//第三种替换式跳转,就是替换跳转前的页面,跳转后想返回上页的结果,跳转的是上上页
//router.replace(’/replace/123456’)

replace应用场景

支付成功跳转支付成功页面,从支付成功返回就是返回购物车页面

在这里插入图片描述

命名路由

就是通过name属性作为跳转别名

1、定义路由的时候,增加name属性

const routes = [
	{ name: 'login', path: '/login', component: '组件' }
]

2、使用编程式路由

router.push({ name: 'login' })

3、组件跳转

<router-link :to="{ name: 'login' }"></router-link>

重定向

1、重定向的使用场景?

一般防止用户跳转到一些没有定义的路由,可以让他跳转到指定的页面。

2、使用方法,redirect指定的是一个路由路径

const routes = [
    { path: '/login', component: Login },
    { path: '/register/:source', component: Register, name: 'register' },
    // 实现如果访问到没定义的页面,强制跳转到登录页面
    { path: '*', redirect: '/login' }
]

嵌套路由

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./vue.js"></script>
    <script src="./vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <router-view></router-view>
    </div>
  </body>

  <script>
    const Blog = {
      template: `
      <div>
        <h1>蟹老板的个人博客</h1>
        <router-link :to="{path: '/blog/article'}">查看文章</router-link>
        <router-link :to="{path: '/blog/userInfo'}">查看个人信息</router-link>
        <router-view></router-view>
      </div>
      `,
    };

    // 文章
    const Article = {
      template: `
      <div>
        <p>第一篇文章</p>  
        <p>第一篇文章</p>  
        <p>第一篇文章</p>  
        <p>第一篇文章</p>  
      </div>
      `
    }
    // 个人信息
    const UserInfo = {
      template: `
        <div>
          <p>姓名:蟹老板</p>
          <p>性别:男</p>
        </div>
      `
    }

    const routes = [
      { path: '/', redirect: '/blog' },
      {
        path: '/blog',
        component: Blog,
        children: [
          {
            //   注意:子路由路径不需要以/开头
            path: 'article',
            component: Article,
          },
          {
            path: 'userInfo',
            component: UserInfo,
          },
        ],
      },
    ];
    const router = new VueRouter({
      routes,
    });
    new Vue({
      el: '#app',
      data: {},
      router,
    });
  </script>
</html>

小结:

1、定义路由配置,把子路由配置到children节点,children接收一个数组,数组和其他路由配置是一样的,都可以接收相同的参数。

path参数开头不要斜杠。

{
        path: '/blog',
        component: Blog,
        children: [
          {
            //   注意:子路由路径不需要以/开头
            path: 'article',
            component: Article,
          },
          {
            path: 'userInfo',
            component: UserInfo,
          },
        ],
      },

2、在父路由加入<router-view></router-view>

命名视图

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>命令路由</title>
    <script src="./vue.js"></script>
    <script src="./vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <router-view name="header"></router-view>
      <router-view name="main"></router-view>
      <router-view></router-view>
    </div>
  </body>

  <script>
    const Header = {
      template: '<div style="width: 100%; height: 100px; border: 1px solid;">头部</div>'
    }

    const Main = {
      template: `<div style="width: 100%; height: 300px; border: 1px solid red;">中间区域</div>`
    }

    const Default = {
      template: `<div style="width: 100%; height: 100px; border: 1px solid blue;">默认路由</div>`
    }

    const routes = [
      // 注意是components,和以前的指定单个组件不一样
      { path: '/', components: { header: Header, main: Main, default: Default } }
    ];

    const router = new VueRouter({
      routes,
    });

    new Vue({
      el: '#app',
      data: {},
      router,
      methods: {

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

小结

命名视图是一种将所有路由展示在页面的视图

导航守卫

当路由发生变化的时候,执行的钩子函数

    // beforeEach当用户跳转到下一个页面的时候会被触发
    router.beforeEach((to, from, next) => {
        // to 目标路由对象(跳转到目标页面)
        // from 从哪个路由过来的对象
        // next 是一个函数,必须执行该函数才会放行
        console.log(to)
        console.log(from)
        // 出现死循环,判断,如果已经进入登录页面,就不要再检查拉
        if (jumpToLogin && to.path !== '/login') {
            next('/login')
        } else {
            next();
        }
    })

router.beforeEach 当从一个页面跳转到另外一个页面的时候会被触发。

to 目标路由对象(跳转到目标页面)

from 从哪个路由过来的对象

next 是一个函数,必须执行该函数才会放行

其他包管理工具yarn

yarn 由facebook提供的包管理工具

因为facebook觉得npm不好用,下载太慢了,经常出错。

安装

切换为国内的下载源

npm config set registry https://registry.npm.taobao.org

通过npm安装yarn

npm install -g yarn

安装Vue-cli方法 https://cli.vuejs.org/zh/

yarn global add @vue/cli

添加环境变量

参考文章:https://www.jianshu.com/p/9308e6abbe44

初始化Vue项目

vue create 项目名字

启动项目

1、进入项目根目录

cd 项目名字

2、启动项目服务器

yarn serve

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gIBwO7DE-1609341216728)(Vue.assets/image-20201115165529653.png)]

Vue项目目录

模块导入规范

ES Model规范

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iElaHqHW-1609341216729)(Vue.assets/image-20201115170440368.png)]

commonjs规范
const fs = require('fs');

前端工程化

1、工程化解决第三方库管理问题

2、帮助我们自动把第三方包合并到一个js文件中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值