vue
简介
- 一套用于构建用户界面的前端框架
- 特性
- 数据驱动视图:随页面发生变化而变化
- 双向数据绑定:操作表单,实现开发者在不操作DOM的前提下获取表单元素最新属性
- MVVM
- M:Model 数据源
- V:View DOM结构
- VM:ViewModel vue实例(核心)
基本使用
-
导入vue.js的script脚本文件
-
声明一个将要被vue所控制的DOM区域
-
创建vm实例对象
<body> <div id='app'></div> </body> <script> const vm = new Vue({ el:'#app', data: { username: 'zhangsan' } }) </script>
指令
内容渲染指令
v-text
-
运用在属性节点上
-
会覆盖原有标签里面的内容,只能渲染纯文本内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-text</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <p v-text="gender">性别</p> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { gender: '女', }, }) </script> </html>
{{}}
-
插值表达式,解决内容覆盖问题,相当于一个占位符
-
只能渲染纯文本内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{}}</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <p>姓名: {{ username }}</p> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { username:'zhangsan' }, }) </script> </html>
v-html
-
运用在属性节点上
-
会覆盖原有标签里面内容,可以渲染带标签的字符串
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-html</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <div v-html="info">111</div> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { info:'<h4 style="color: red">22</h4>' }, }) </script> </html>
属性绑定指令
v-bind
-
简写 :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-bind</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <input type="text" v-bind:placeholder="tips"> <input type="text" :placeholder="tips1"> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { tips: '请输入用户名', tips1: '请输入密码', }, }) </script> </html>
事件绑定指令
v-on
-
简写 @
-
DOM原生时间onclick、oninput替换为vue绑定事件为v-on:click简写为@click
-
函数可以传递参数其中不加小括号表示不传参,添加小括号实现传递参数
-
vue原生对象$event
- $event就是原生DOM的事件对象event
- 当传递参数是需要将原生对象 e v e n t 传入,当无参数传入时默认传递了 event传入,当无参数传入时默认传递了 event传入,当无参数传入时默认传递了event原生对象
-
事件修饰符
- 添加在事件绑定后面
- 阻止默认行为 @click.prevent === e.preventDefault();
- 阻止事件冒泡 stop
- 绑定事件只触发一次 once
-
按键修饰符
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-on</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <p>值:{{ count }}</p> <button v-on:click="add">+1</button> <button @click="sub(2)">-2</button> <h4>如果为偶数按钮背景则为红色,如果为奇数则取消背景颜色</h4> <p>value:{{ value }}</p> <button v-on:click="add1(1, $event)">+1</button> <br> <h4>事件修饰符:打印点击事件阻止链接跳转</h4> <a href="www.baidu.com" @click.prevent="show">跳转链接</a> <h4>按键修饰符:按下esc键清除文本框内容,按下enter打印内容</h4> <input type="text" @keyup.esc="clear" @keyup.enter="enter" </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { count: 0, value: '' }, methods: { // 创建函数 add(){ // 修改data里面数据:调用vm对象中的data属性的count值 其中this === vm ++this.count; }, sub(n){ this.count -= n; }, } }) </script> </html>
双向绑定指令
v-model
-
在不操作DOM的前提下快速获取表单数据
-
只有表单元素使用才有意义
-
修饰符
- number:将用户输入字符串转换为数值类型;
- trim:自动过滤用户首位空白字符;
- lazy:离开输入框失去焦点才会更新
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-model</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <p>用户名:{{username}}</p> <input type="text" v-model="username1"> <!--v-model实现复选 选取value值--> <select name="" id="" v-model="city"> <option value="">请选择城市</option> <option value="1">北京</option> <option value="2">上海</option> <option value="3">广州</option> </select> <input type="text" v-model.number="n1"> + <input type="text" v-model.number="n2"> = <span>{{n1+n2}}</span> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { username:'zhangsan', city: '', n1: 1, n2: 2, }, }) </script> </html>
条件渲染指令
v-if
- 动态创建或者移除元素
v-show
- 动态为元素添加或者移除dispaly:none样式,实现元素显示或者隐藏
v-else-if
-
需要配合v-if使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-for</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <!--v-if: 动态的创建或者移除元素--> <p v-if="flag">v-if控制的元素</p> <!--v-show: 动态为元素添加或者移除dispaly:none样式,实现元素显示或者隐藏--> <p v-show="flag">v-show控制的元素</p> <!--v-else-if--> <p>v-else-if</p> <div v-if="type === 'A'">优秀</div> <div v-else-if="type === 'B'">良好</div> <div v-else-if="type === 'C'">一般</div> <div v-else>差</div> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { flag: true, type: 'A', }, }) </script> </html>
列表渲染指令
v-for
-
<tr v-for="(item,index) in list" :key="item.id">
- 第一个参数item表示列表中循环的元素,第二个参数index代表索引
- 每使用一个v-for指令都需要绑定一个key属性
- key属性的值只能时字符串或者数字类型,尽量将id作为key值
- key的值不能重复,否则报duplicate keys detected错误
- key值不可以使用索引
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-for</title> <link rel="stylesheet" href="lib/bootstrap.css"> </head> <body> <div id="app"> <table class="table table-bordered table-hover table-striped"> <thead> <th>索引</th> <th>ID</th> <th>姓名</th> </thead> <tbody> <tr v-for="(item,index) in list" :key="item.id"> <td>{{index}}</td> <td>{{item.id}}</td> <td>{{item.name}}</td> </tr> </tbody> </table> </div> </body> <!--1、导入vue.js--> <script src="lib/vue-2.6.12.js"></script> <script> <!----> //2、创建vue实例对象 const vm = new Vue({ //控制哪个区域 el后接选择器 el: '#app', // 渲染页面的数据 data data: { list: [ {id:1, name:'zs'}, {id:2, name:'ls'}, {id:3, name:'ww'}, ], }, methods: { add1(n, e){ this.value += n; if (this.value%2 == 0){ e.target.style.backgroundColor = 'red'; }else { e.target.style.backgroundColor = ''; } }, show(){ console.log('点击了a链接') }, clear(e){ // 清空文本框 e.target.value = ''; }, enter(e){ console.log(e.target.value); } } }) </script> </html>
过滤器
-
使用位置:插值表达式及v-bind属性绑定
-
通过管道符进行调用
-
过滤器函数必须定义到filters下,本质上是一个函数 过滤器必须要有一个返回值
-
过滤器函数形参永远都是管道符前面的值
-
全局过滤器
- Vue.filter
- 全局过滤器放在在上方
-
私有过滤器
- 只能在当前vm实例所控制的el区域内使用
- 通过vue实例的filters节点属性实现
- 本质上为一个函数,必须有返回值
-
过滤器可通过串联调用多个过滤器
- a|b|c|d
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>过滤器</title> </head> <body> <h2 style="color: pink">过滤器使用</h2> <div id="app"> <p>message的值是:{{message|capi}}</p> <p>message的值是:{{message|capi1}}</p> </div> <div id="app2"> <p>message的值是:{{message|capi}}</p> <p>message的值是:{{message|capi1}}</p> </div> </body> <script src="lib/vue-2.6.12.js"></script> <script> // 使用Vue.filter定义全局过滤器 Vue.filter('capi1', function (str){ return str.charAt(0).toUpperCase(); }) const vm = new Vue({ el: '#app', data: { message:'hello' }, filters: { // 过滤器函数形参中的val永远都是管道符前面的值 // 定义到filters的过滤器叫做私有过滤器只能自己使用 capi(val){ // charAt接收索引值表示把字符串中的索引对应的字符取出来 const first = val.charAt(0).toUpperCase(); const other = val.slice(1); return first+other; } } }); const vm2 = new Vue({ el: '#app2', data: { message:'hello' } }); </script> </html>
侦听器
-
允许开发者监视数据变化,实现特定动作
-
所有侦听器必须放在watch节点下
-
本质上是一个函数 要监视哪个数据的变化就把数据名作为方法名
-
函数(方法)形式的侦听器
- 在刚进入页面的时候不会被自动触发 监听对象属性发生变化不会触发监听器
-
对象格式的侦听器
-
immediate: true
- 选项默认值为false 当为true时进入页面就会进行触发
-
deep: true
- 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
-
如果要侦听的是对象的子属性则必须包裹一层单引号,类似于函数侦听器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>侦听器</title>
</head>
<body>
<div id="app">
<span>函数形式侦听器</span><input type="text" v-model="username">
<br>
<span>对象格式侦听器</span><input type="text" v-model="username1">
<br>
<span>监视对象中属性变化</span><input type="text" v-model="info.username">
</div>
</body>
<script src="lib/jquery-v3.6.0.js"></script>
<script src="lib/vue-2.6.12.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
username: 'user',
username1: 'user',
info: {
username: 'admin'
}
},
methods: {
},
watch: {
// 函数形式侦听器
// newVal为新值 oldVar为旧值 新值在前旧值在后
username(newVal, oldVal){
console.log(newVal + ', '+ oldVal)
// if (newVal='') return;
// // 调用jQuery中的ajax发送请求,判断用户名是否可用
// $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) {
// console.log(result);
// })
},
// 对象格式的侦听器
username1: {
// 侦听器处理函数
handler(newVal, oldVal){
console.log(newVal + ', '+ oldVal)
},
// 选项默认值为false 当为true时进入页面就会进行触发
immediate: true,
// 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
deep: true
},
// 对象格式的侦听器
info: {
// 侦听器处理函数
handler(newVal, oldVal){
console.log(newVal + ', '+ oldVal)
},
// 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
deep: true
},
// 如果要侦听的是对象的子属性则必须包裹一层单引号
'info.username'(newVal, oldVal){
console.log(newVal,oldVal)
}
}
})
</script>
</html>
计算属性
-
所有计算属性都要定义到computed节点之下 计算属性在定义的时候都要定义成方法格式
-
计算属性的本质是一个属性 ,与data中属性使用方法一致
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>计算属性</title> <style> .box { width: 200px; height: 200px; border: 1px solid black; } </style> </head> <body> <div id="app"> <span>r</span><input type="text" v-model.number="r"><br> <span>g</span><input type="text" v-model.number="g"><br> <span>b</span><input type="text" v-model.number="b"> <div class="box" :style="{backgroundColor: rgb}">{{rgb}}</div> </div> </body> <script src="lib/vue-2.6.12.js"></script> <script> const vm = new Vue({ el: '#app', data: { r: 0, g: 0, b: 0 }, computed: { // rgb方法相当于data中属性,与data中属性使用方法一致 rgb(){ // $ 模板字符串 return `rgb(${this.r}, ${this.g}, ${this.b})` } } }) </script> </html>
vue-cli
- 中文官网:https://cli.vuejs.org/zh/
- 安装:npm install -g @vue/cli
- 创建vue:
- vue create 项目名称
- 建议选择Manually select features
- babel:编译器
- TypeScript:微软
- Progressive web App(PWA) support:渐进式布局
- Router:路由
- CSS Pre-processors:CSS预处理器
- Linter/Formtter:约束代码风格
- Unit Testing:单元测试
- E2E Testing:E2E测试
- 切换到创建目录
- 运行项目:npm run serve
src目录结构
- assets:静态资源 如:css、图片
- components:程序员封装的可复用组件
- main.js:项目入口文件
- App.vue:项目跟组件
组件
组件三部分
-
template:模板结构
- 必须存在
- 只起到包裹性质的作用,不会渲染成真正的DOM元素
- 只能包含唯一节点
-
script:行为
- 组件中的相关data数据、methods方法等都需要定义到export defasult所导出的对象中
- 格式为 export default {}
- 其中data必须为函数,不能直接指向一个数据对象,通过return返回数据对象
-
style:样式
- 添加less语法:在style标签中添加lang="less"属性
-
组件关系
- 父子关系
- 兄弟关系
组件使用
- 注册组件
- 全局组件
- 在main.js入口文件中使用import导入需要的组件
- 通过Vue.component(参数1,参数2) 注册组件
- 参数1:字符串格式,表示组件的注册名称
- 参数2:需要被全局注册的那个组件
- 私有组件
- 在需要使用该组件的vue文件中通过import导入组件
- 通过components节点注册组件
- 全局组件
- 以标签的形式使用注册的组件
组件样式冲突
- 实现组件内部样式只影响该组件的使用
- 方法1
- 给当前组件模板结构中所有标签都加上同意属性 data-v-001
- 使用时带上该属性 如:h3[data-v-001]
- 方法2
- 给当前组件中style节点加入scoped属性:
<style scoped></style>
- 该方式类似于h3[data-v-001]
- 给当前组件中style节点加入scoped属性:
- 样式穿透
- 更改子组件
- 在需要改变的子组件样式前添加/deep/前缀 :/deep/h5
- 该方式类似于[data-v-001] h5
生命周期
创建阶段
- 创建对象new Vue()
- beforCreate
- props/data/methods尚未被创建
- created
- props/data/methids被创建
- 调用methods中的方法发起ajax请求拿数据
- beforeMount
- 生成模板结构,但DOM还未生成
- mounted
- 生成DOM结构操作DOM元素
运行阶段
- 最少被执行0次,只有数据发生改变才会执行
- beforeUpdate
- 当数据发生改变执行此时页面为旧的,数据为新的
- updated
- 实现数据与界面同步
销毁阶段
- beforeDestory
- destoryed
数据共享
父传子
-
通过自定义属性props实现
-
子组件中封装 props:[‘自定义属性A’,‘自定义属性B’]
- 数据可直接在模板结构中使用
- 只读属性,不能直接修改props的值,否则报错
- 若要改变自定义属性的值一般在data属性中将this.自定义属性赋值给一个接收对象,通过调用接收对象实现值的修改
- 其中可为属性添加配置选项
- props: {自定义属性A: {配置选项}, 自定义属性B: {配置选项}}
- 该组件被使用时,如果没有传递自定义属性,则可通过defalut设置默认值
- 自定义属性也可以通过type属性定义该值的类型
- 当添加requred: ture 属性后,若父组件不传递值则会报错
-
父组件中在子组件对于标签中配合v-bind属性实现
-
例如子组件为Left.vue,父组件为App.vue
-
子组件:
<template> <div class='left-container'> <h3>子组件</h3> <p>msg的值为:{{msg}}</p> <p>user对象:{{user}}</p> <p>姓名:{{user.username}}</p> </div> </template> <script> export default { props:['msg',['user']] } </script> <style> .left-comtainer { 样式 } </style>
-
父组件
<template> <div class='app-container'> <h3>父组件</h3> <div class="box"> <Left :msg="message" :user="userinfo"></Left> </div> </div> </template> <script> import Left from "@/components/Left"; export default { components:{ Left, }, data() { message: 'hello', userinfo: {username:'wsc', age: 18} } } </script> <style> .left-comtainer { 样式 } </style>
子传父
-
通过自定义事件来实现
-
子组件通过this.$emit实现
- this.$emit(“自定义事件名称”,传递参数)
-
父组件配合v-on实现
- 在调用的子组件标签中添加@自定义事件名称=“方法名”
- 在methods中添加方法 方法名(参数){ }
-
例如子组件为Right.vue,父组件为App.vue
-
子组件:
<template> <div class='left-container'> <h3>子组件---{{ count }}</h3> <button @click="add">+1</button> </div> </template> <script> export default { data() { return { count: 0 } }, methods: { add(){ this.count+=1 this.$emit('numChage', this.count) } } } </script> <style> .left-comtainer { 样式 } </style>
-
父组件
<template> <div class='app-container'> <h3>父组件---{{ countFronSon }}</h3> <div class="box"> <Right @numChange="getNewCount"></Right> </div> </div> </template> <script> import Right from "@/components/Right"; export default { data() { return: { // 获取子组件的值 countFromSon: 0 } }, components:{ Right, }, methods: { getNewCount(val){ this.countFromSon = val } } } </script> <style> .left-comtainer { 样式 } </style>
兄弟传值
-
通过EventBus进行数据共享
-
创建eventBus.js模块,并向外共享一个Vue实例对象
import Vue form 'vue' // 向外共享Vue实例对象 export default new Vue()
-
在数据发送方,通过bus.$emit(‘事件名称’, 要发送的数据)触发自定义事件
<template> <div class='app-container'> <h3>发送方</h3> <button @click="sendMsg">发送数据</button> </div> </template> <script> import bus from "./eventBus.js"; export default { data() { return: { dataMsg: '需要发送的数据' } }, methods: { sendMsg(){ bus.$emit('share', this.dataMsg) } } } </script> <style> .left-comtainer { 样式 } </style>
-
在数据接收方,调用bus.$on(‘事件名称’, 事件处理函数)方法注册一个自定义事件
<template> <div class='app-container'> <h3>接收方</h3> <p>{{msgFromSend}}</p> </div> </template> <script> import bus from "./eventBus.js"; export default { data() { return: { msgFromSend: '' } }, created() { bus.$on('share', val => { this.msgFromSend = val }) } } </script> <style> .left-comtainer { 样式 } </style>
ref引用
-
在不通过原生方法操作DOM的情况下,获取DOM元素和组件的引用
-
$refs
- vue组件实例中都包含一个$refs对象
- DOM元素的引用
<template> <div class='app-container'> <h3 ref='hsRef'>根组件</h3> <button @click='show'>点击实现样式改变</button> </div> </template> <script> export default { methods: { show(){ this.ref.h3Ref.style.color = 'red' } } } </script> <style> .app-comtainer{ 样式 } </style>
-
组件引用
- 子组件
<template> <div class='left-container'> <h3>子组件</h3> <p>count: {{ count }}</p> <button @click="cpunt+=1">+1</button> <button @click="resetCount">重置</button> </div> </template> <script> export default { data() { return { count: 0 } }, methods: { resetCount(){ this.count = 0 } } } </script> <style> .left-comtainer { 样式 } </style>
- 父组件
<template> <div class='app-container'> <h3>父组件</h3> <button @click='resetCount'>重置子组件count</button> <Left ref='comLeftRef'></Left> </div> </template> <script> import Left from "@/components/Left"; export default { components:{ Left, }, methods: { resetCount(){ this.$refs.comLeftRef.count = 0 // 也可以调用子组件中的方法进行实现 // this.$refs.comLeft.resetCount() } } } </script> <style> .left-comtainer { 样式 } </style>
-
this.$nextTick(cb)
- 实现将cb回调推迟到下一个DOM更新周期进行执行
- 保证cb回调函数可以操作到最新的DOM元素
<template> <div class='app-container'> <h3>父组件</h3> <input type='text' @blur="showButton" ref='inputRef' v-if='inputVisible'> <button @click='showInput' v-else>展示输入框</button> </div> </template> <script> export default { data() { return { // 默认隐藏输入框 inputVisibler: false } } methods: { showButton() { this.inputVisibler = false }, showInput() { this.inputVisibler = true // 展示后自动获取焦点 this.$nextTick(() =>{ this.$refs.inputRef.focus() }) } } } </script> <style> .left-comtainer { 样式 } </style>
动态组件
-
动态实现组件的显示与隐藏
-
component
- 相当于一个占位符,实现组件的显示与隐藏
- 其中is属性可动态指定需要渲染的组件
-
keep-alive
-
保持动态组件状态,防止组件被销毁,把内部组件进行缓存
-
当组件被缓存时会自动触发组件的deactivated生命周期函数
-
当组件被激活时会自动触发组件的activated生命周期函数
-
deactivated与activated函数只有在使用keep-alive标签才具有作用
-
当组件第一次被创建时,会触发created生命周期,也会触发activated生命周期
-
当组件再次被激活时,不会触发created生命周期,会触发activated生命周期
-
include
- 只有指定组件可被缓存 <keep-alive include: “组件名称”>
- 当组件不提供name属性,则注册名默认为组件名
- 当组件提供了name顺序,调用组件时则需要使用name属性定义的名称
- 例如:name: ‘yaya’ 调用:<keep-alive include: “yaya”>
- exclude指定的组件不可被缓存,两者不能同时使用
<template>
<div class='app-container'>
<h3>父组件</h3>
<keep-alive include="Left">
<component :is="comName"></component>
</keep-alive>
<button @click="comName ='Left'">展示Left组件</button>
<button @click="comName ='Right'">展示Right组件</button>
</div>
</template>
<script>
import Left from "@/components/Left";
import Right from "@/components/Right";
export default {
data() {
return {
// 默认展示Left组件
comName: 'Left'
}
},
components:{
Left,
Right
}
}
</script>
<style>
.left-comtainer {
样式
}
</style>
插槽
-
在组件封装期间为用户预留的内容占位符
-
<slot>
定义插槽<slot name="default">
- 每一个slot都会有一个名称,若不写默认为default
- 其中带名称的插槽称之为具名插槽
- 在封装中可以对外传递数据,数据存放在
<slot>
标签中- 例如
<slot name="contentSlot" msg="hello vue.js"></slot>
- 这种称之为作用域插槽
- 例如
<template> <div class='left-container'> <h3>Left 组件</h3> <slot name="default">这是default插槽默认内容</slot> <div> <slot name="contentSlot" msg="hello vue.js"></slot> </div> </div> </template> <script> export default { } </script> <style> .left-comtainer { 样式 } </style>
-
为插槽提供内容
- 在
<template>
元素上使用v-slot指令,并以v-slot的参数的形式提供名称- 例:
<template v-slot="default"></template>
- 其中template只起包裹作用
- v-slot只能使用在template属性上
- v-slot可简写为 #
- 在接收作用域插槽时可通过#插槽名称="scope"接收
- 接收为一个对象
- 若不传则为一个空对象
- 调用方式scope.键
- 接收时也可通过结构赋值的方式简化数据的接收过程
- 例:
<template #contentSlot="{{scope.msg}"></template>
- 例:
- 例:
<template> <div class='left-container'> <h3>App 组件</h3> <Left> <template v-slot:default></template> <template #contentSlot="scope"> <p> {{ scope.msg }} </p> </template> </Left> </div> </template> <script> export default { } </script> <style> .left-comtainer { 样式 } </style>
- 在
自定义指令
-
私有自定义指令
- 在vue组件中,在directives节点下声明私有自定义指令
-
全局自定义指令
- 在main.js文件中通过Vue.directive()可实现对全局自定义指令
-
使用
- 在使用时需要添加 v- 前缀
- 在使用时通过 = 可为当前指令进行动态绑定参数值
<template> <div class="app-container"> <h1 v-color>App根组件</h1> <p v-color1="color1">自定义组件</p> <!-- 在双引号中再包裹一层单引号表示引用具体数据,不包裹则表示引用对应属性的值(键获取值)--> <p v-color1="'red'">自定义组件1</p> <!-- 改变div的背景颜色--> <div class="box" v-backgroundColor="backgroundColor"></div> <button @click="show">改变div颜色</button> </div> </template> <script> import Left from "@/components/Left"; import Right from "@/components/Right"; import Article from "@/components/Article"; export default { data() { return { color1: 'blue', backgroundColor: 'pink' } }, components: { Left, Right, Article }, methods: { show(){ this.backgroundColor = 'blue' } }, // 私有指令 directives: { // 定义一个color指令指向一个配置对象 color: { // 当指令第一次绑定到元素上时会触发bind函数 // 形参中的el表示当前指令所绑定的那个DOM对象 bind(el){ el.style.color = 'red' } }, color1: { // binding为接收对象,其中binding.value则为调用时等号所调用的值 bind(el, binding){ el.style.color = binding.value } }, // backgroundColor: { // // 第一次绑定时候执行,之后不在执行 // bind(el,binding){ // el.style.backgroundColor = binding.value // }, // // 第一次不执行,在DOM结构更新的时候会触发update函数 // update(el,binding){ // el.style.backgroundColor = binding.value // } // } // 当bind和update逻辑完全一样可实行简写形式 backgroundColor(el,binding){ el.style.backgroundColor = binding.value }, } } </script> <style lang="less"> .app-container { padding: 1px 20px 20px; background-color: #efefef; } .box { height: 200px; width: 200px; } </style>
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false // 全局自定义指令 // 当bind和update逻辑完全一样可实行简写形式 Vue.directive('color111', function (el, binding) { el.style.color = binding.value }) Vue.directive('color112', { bind(el, binding) { el.style.color = binding.value }, update(el, binding) { el.style.color = binding.value }, }) new Vue({ render: h => h(App), }).$mount('#app')
路由
-
SPA:在web网站中只有唯一一个HTML界面
-
在SPA项目中进行不同功能之间的切换需要通过前端路由实现、
-
路由:Hash地址与组件之间的对应关系
-
vue-router
- 官方网址:https://router.vuejs.org/zh/
- vue2中安装:npm install vue-router@3.5.2
- 创建路由模块:在src源代码目录中,新建router/index.js路由模块,初始化代码如下
// src/router/index 就是当前项目的路由模块 // 1、导入vue就vue-router包 import Vue from "vue"; import VueRouter from "vue-router"; // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件 // Vue.use()作用安装插件 Vue.use(VueRouter) // 3、创建路由实例对象 const router = new VueRouter({}) // 4、向外共享路由实例对象 export default router
- 将导入的路由模块挂载到src/main.js入口文件中
import Vue from 'vue' // 更改路径通过App2实现路由 import App from './App2.vue' // 1、导入路由模块 // 在模块化导入时如果给定的为文件夹,则默认导入文件夹下index.js文件 import router from "@/router"; Vue.config.productionTip = false new Vue({ render: h => h(App), // 在Vue项目中要想实现路由,必须通过下列方式实现挂载 // 2、router: 路由的实例对象,当属性名和实例对象一致时可进行简写为router router }).$mount('#app')
- 路由链接
<router-link to='"/home">首页</router-link>
- 在斜线(/)后的参数称之为路径参数,通过this.$route.params进行获取
- 在哈希地址中问号(?)后面的参数称之为查询参数,通过this.$route.query进行获取
- this.$route.path获取哈希路径
- this.$route.fullPath获取完整地址
- router-link相当于a链接中的a标签
- to相当于a链接中的href属性
- 占位符
<router-view></router-view>
-
路由规则
- 在src/router/index.js路由模块中,创建VueRouter时通过routers数组声明路由规则
- 实现Hash地址与组件之间对应关系
- 其中对应的组件需要通过import导入
- path表示匹配的hash地址,component表示需要展示的路由组件
- 重定向:redirect 实现界面跳转的指定页面
// src/router/index 就是当前项目的路由模块 // 1、导入vue就vue-router包 import Vue from "vue"; import VueRouter from "vue-router"; // 导入需要的组件 import Home from "@/components/Home"; import Movie from "@/components/Movie"; // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件 // Vue.use()作用安装插件 Vue.use(VueRouter) // 3、创建路由实例对象 const router = new VueRouter({ // 定义Hash地址和组件之间的对应关系 routes:[ // 路由规则 // 重定向:redirect {path: '/', redirect:'/home'}, {path: '/home', component:Home}, {path: '/movie/', component:Movie}, ] })
-
嵌套路由
- 通过chindren属性声明子路由规则
- 如果children中,某个路由规则的puth值为空字符串,则这条路由规则为默认子路由
- 默认子路由相当于进行了redirect重定向只是不存在跳转
{ path: '/about', component:About, // 子路由规则 children属性 children: [ // 默认子路由相当于redirect重定向 {path:'',component:Tab1}, {path:'tab1',component:Tab1}, {path:'tab2',component:Tab2} ], // redirect:'/about/tab1' },
-
动态路由
- 为提高路由规则的复用性,把Hash地址中可变部分定义为参数项
- 通过英文冒号定义路由的参数项
- 获取参数方式
- 方式1:在组件中可通过this.$route.parans.id 获取参数
- 方式2:在当前路由规则中开启props传参,在组件中通过props: [‘id’]获取参数
- 路由规则 {path: ‘/movie/:id’, component:Movie, props:true}
- 获取参数 props: [‘id’]
- route为路由的参数对象
-
编程式导航
- 通过API实现的导航
- router为路由的导航对象
- this.$router.push(‘hash地址’)
- 跳转到指定的hash地址,并添加一条历史记录
- this.$router.replace(‘hash地址’)
- 跳转到指定的hash地址,并替换当前的历史纪录
- this.$router.go(数值)
- 数据为几表示前进或者倒退多少
- this.$router.back()
- 后退一层
- this,$router.forward()
- 前进一层
-
导航守卫
- 控制路由的访问权限
// src/router/index 就是当前项目的路由模块 // 1、导入vue就vue-router包 import Vue from "vue"; import VueRouter from "vue-router"; // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件 // Vue.use()作用安装插件 Vue.use(VueRouter) // 3、创建路由实例对象 const router = new VueRouter() // 为router实例对象,声明全局前置导航守卫 // 只要发送了路由的导航跳转必然会触发回调函数 router.beforeEach(function (to,from,next) { // to表示将要访问的路由信息 // console.log(to) //from表示将要离开的路由信息对象 // console.log(from) // next()函数表示放行 // next() // 当用户拥有后台主页访问权限,直接放行next() // 当用户没有后台主页访问权限,强制跳转到其他界面next('/login') // 当用户没有后台主页访问权限,不允许跳转到后台主页next(false) // a、拿到用户将要访问的hash地址 // b、判断hash地址是否等于/main 如果等于则需要登录才能访问 如果不等于则不需要登录直接放行 if (to.path === '/main'){ // c、读取localStorage中的token值 如果有token则放行 如果没有则强制跳转到/login登录界面 const token = localStorage.getItem('token') if (token){ next() }else { next('/login') } }else{ next() } }) // 4、向外共享路由实例对象 export default router