Vue.js
1. 介绍
渐进式框架
HTML+CSS+JS =视图:给用户看的,刷新后台数据
Vue-UI:ICE
MVC:
View:
DATA:
VM:数据双向绑定
UI框架:Ant-Design、ElementUI、iview、ice、妹子UI、vue-element-admin
JavaScript构建工具:WebPack
https://cdn.jsdelivr.net/npm/vue/dist/vue.js
特点和功能
- 解耦视图和数据
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
MVVM
2. 使用
==代码规范:==缩进两个空格
创建项目
引入配置:
- cdn
<script src="https://unpkg.com/vue@next"></script>
- 下载和引入
- npm安装
-
创建DOM元素,使其成为Vue实例的挂载点,Vue实例中的所有数据这能在挂载点中使用
<!-- 取一个id 用于给vue进行绑定 --> <div id=app> </div> -
通过
new Vue
来创建实例对象<!-- 创建vue对象 --> <script> const vm = new new Vue({ // 绑定元素id el: "#app", // 数据 data: { message: "Hello,World!" } }); </script> -
el
属性指定当前Vue实例的挂载点 -
data
中是模型数据,这些数据依赖于当前Vue的实例,可以通过控制台输入app.msg
来查看数据
<!-- 取一个id 用于给vue进行绑定 --> <div id="app"> <!-- 取出data里面的数据 --> {{message}} </div>
- 可以通过插值表达式使用data中的数据
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 所有的数据都存在data里面 data: { name: "ss", // 使用v-show指令时,这里的值需要为null age: null } })
<!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>Document</title> </head> <body> <div id="app"> <div> <!-- 指令 --> <!-- v-model把input的内容指定到指定的位置· --> <input type="text" v-model="name"> <span v-show="name">你的名字是{{name }}</span> </div> <!-- 如果data对象里面没有定义这个值,那么就会报错 --> <span>{{sex}}</span> <div> <input type="text" v-model="age"> <!-- v-show="age",如果age有值时才显示 --> <span v-show="age">sss{{age}}</span> <!-- v-if同样也可以隐藏,区别在于这个会把数据删除 --> <!-- <span v-if="age">sss{{age}}</span> --> </div> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
3. 实例Vue传入的options
4. Vue生命周期
-
又名:生命周期回调函数、生命周期函数、生命周期钩子
-
生命周期函数中的this指向是vm或组件实例对象
-
Vue在关键时刻帮我们调用的一些特殊名称的函数,生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
const vm = new Vue({ el: '#app', data: { movies: ['一人之下', '全职高手', '风铃玉袖', '精灵王座'] }, // 创建之前调用 beforeCreate: function() { }, // 创建之后调用 created: function() { }, // 挂载完成调用----只执行一次 mounted: function() { } })
5. 插值
-
Mustache语法:使用两个大括号
加号进行拼接
进行运算
-
v-once指令:被修饰的值不能够进行二次修改
-
v-html:用于解析html
<body> <div id="app"> <h2 v-html="url"></h2> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { url: '<a href="https://www.baidu.com" >百度</a>' } }) </script> </body> -
v-text:直接展示文本,会覆盖掉已经有的文本
<body> <div id="app"> <h2 v-html="url"></h2> <h1 v-text="message"></h1> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { message: '你好!', url: '<a href="https://www.baidu.com" >百度</a>' } }) </script> </body> -
v-pre:不进行任何解析,把被修饰的内容原封不动输出,类似pre标签
<h1 v-pre>{{message}}</h1> -
v-cloak:再vue解析之前这个属性存在,解析之后就不存在,通过这个属性加上style可以控制当vue没加载好时,不任何显示内容
<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>Document</title> <style> [v-cloak]{ display: none; } </style> </head> <body> <div id="app" v-cloak> <h2 v-html="url"></h2> <h1 v-text="message"></h1> <h1 v-pre>{{message}}</h1> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { message: '你好!', url: '<a href="https://www.baidu.com" >百度</a>' } }) </script> </body>
6. 常用指令
v-for
- 列表循环:
<div id="app"> <ul> <li v-for="item in movies">{{item}}</li> </ul> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { movies: ['一人之下', '全职高手', '风铃玉袖', '精灵王座'] } }) </script>
使用F12添加
- 使用:迭代JSON
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 所有的数据都存在data里面 data: { // 使用v-for迭代数组 // foodList: ['香菜', '洋葱', '番茄'], //创建数组 // 一般用于迭代JOSN foodList: [{ name: 'nihao', price: 13 }, { name: '好的', price: 13 }, { name: '真的是', price: 13 }, { name: '干嘛', price: 13 }] } })
<!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>Document</title> </head> <body> <div id="app"> <ul> <!-- v-for : 迭代后存储的参数名字 in data的对象数组 --> <!-- <li v-for="food in foodList">{{food.name}}</li> --> <!-- 迭代对象 --> <li v-for="food in foodList">{{food.name}}+{{food.price}}</li> </ul> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
获取value,key,index
<div v-for="(value,key,index) in items"> {{ value }} </div>
组件的key属性
尽量保持唯一性
添加key可以提高数组遍历渲染后插入再插入数据时的性能
有key就会和内容一一对应
<div id="app"> <ul> <li v-for="item in letters" :key="item">{{item}}</li> </ul> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { letters: ['A', 'B', 'C', 'D'] } }) </script>
数组的响应式方法
-
push在数组的最后添加元素
-
pop删除数组的最后一个元素
-
shift删除数组的第一个元素
-
unshift在数组的最前面添加元素
-
splice删除/插入/替换元素
-
sort排序数组
-
reverse反转
通过数组下标修改不是响应式的
如果非要通过下标修改:
Vue.set(要修改的对象,索引值,修改后的值)
v-bing
用于动态绑定数据和元素属性
语法糖:直接写冒号==:==
-
<body> <div id="app"> <img v-bind:src="url" alt="#"> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { url: 'https://cdn.pixabay.com/photo/2021/08/02/11/03/hallelujah-6516410__340.jpg' } }) </script> </body> -
动态绑定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>Document</title> <style> .active { background: red; } </style> </head> <div id="app"> <!-- v-bing:属性=“数据名” 也可以在F12里面动态更换 也可以绑定类 可以省略前面的v-bing只要冒号 --> <!-- :class="active: isActive" 第一个为要添加的类 第二个为判断,如果是true就执行 --> <a v-bind:href="url" :class="{active: isActive}">的</a> </div> <body> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </body> </html>
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 所有的数据都存在data里面 data: { url: 'https://www.baidu.com', isActive: true, } })
<style> .active { color: red; } </style> </head> <body> <div id="app"> <img v-bind:src="url" alt="#"> <h1 v-bind:class="getClass()">444</h1> </div> <script src="../js/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { url: 'https://cdn.pixabay.com/photo/2021/08/02/11/03/hallelujah-6516410__340.jpg', isActive: true }, methods: { getClass: function() { return { ' active': this.isActive } } } }) </script> </body>
-
动态绑定class (数组语法)
<h1 v-bind:class="['active',line]"></h1> -
动态绑定style
<div id="app"> <!-- {CSS属性名:属性值} --> <h1 v-bind:style="{'font-size':'100px'}">测试</h1> </div> -
数组语法
v-on
用于绑定事件,事件监听
语法糖:@
修饰符:
防止冒泡事件:stop
阻止默认事件:如表单默认提交–prevent
监听键盘事件:keyup
只回调一次:once
监听组件根元素的原生事件:native
<!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>Document</title> </head> <body> <div id="app"> <!-- v-on:click="OnClick" v-on:事件类型=“方法名” v-on可以缩写成@ --> <!-- 给一个目标绑定多个事件类型 v-on="{事件类型:方法名,事件类型:方法名}"--> <button v-on="{mouseenter: onEnter,mouseleave: outLeave}" v-on:click="OnClick">点我</button> <!--submit.prevent 防止表单自动提交 v-on:submit.stop防止冒泡事件 --> <!-- 键盘事件keyup 识别是否是回车键 keyup.enter 回车事件要和提交事件一起使用--> <form @keyup.enter="on" @submit.prevent="ont"> <input type="text"><button type="submit">顶顶顶</button> </form> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 方法存储在这里 methods: { OnClick: function() { console.log("你好") }, onEnter: function() { console.log("鼠标进来") }, outLeave: function() { console.log("鼠标出去") }, on: function() { console.log("提交") }, ont: function() { console.log("提交") }, } })
计时器:
<div id="app"> 当前:{{counter}} <button v-on:click="counter++">+</button> <button v-on:click="counter--">-</button> </div> <script src="../js/vue.js"></script> <script> let vm = new Vue({ el: "#app", data: { counter: 0 } }) </script>
传参:如果不需要传参时括号可以省略,但是方法里面必须要参数的情况除外(如果不省略小括号且不传值,就会使用默认值undefined)
<div id="app"> <button @click="btn">1</button> <!-- 如果在需要 参数的事件中,省略了小括号,那么vue会把浏览器生成的Event对象当成应该参数进行传值--> <button @click="btn2">1</button> <!-- undefined --> <button @click="btn2()">1</button> <button @click="btn2('aa')">1</button> <!-- 需要event对象 和 其它参数 --> <!-- 需要手动获取event --> <button @click="btn3($event,11)">1</button> </div> <body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', methods: { btn() { console.log('这个可以省略括号') }, btn2(abd) { console.log(`这个不能省略`, abd) }, btn3(event, abc) { console.log(`这个不能省略`, event, abc) } } }) </script>
v-model
用于双向绑定,基本上用于表单绑定
1. 在input元素的使用
修饰符:
lazy 惰性更新
trim 去除文本的前后空格(要在控制台才能看出结果)
number 数字,会把字符串的数字转换为数字类型 ,同时会自动使用科学计数法
typeof:可以判断值得类型
<!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>Document</title> </head> <body> <div id="app"> <!-- v-model.lazy惰性更新 在输入完成后焦点离开输入框后才进行反应 --> <!-- v-model.trim 去除文本的前后空格 --> <!-- v-model.number 数字,会把字符串的数字转换为数字类型 ,同时会自动使用科学计数法--> <input type="text" v-model.number="name"> <!-- pre标签会解析文本内的所有东西包括空格 ,会把所有空格全部解析出来 --> <pre>{{name}}</pre> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 方法存储在这里 data: { name: 'hhh', }+ })
2. 双向绑定的原理
<body> <div id="app"> <input type="text" :value="name" @input="valueChange"> {{name}} </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { name: '君子慎独' }, methods: { valueChange(event) { this.name = event.target.value } } }) </script> </body>
原理就是使用v-bing指令的value属性来把name的值绑定到input上,使用v-on指令的input事件来监听input同时触发方法更换name的值
在其他元素的使用
还能在这两个元素上使用:
<textarea name="" id="" cols="30" rows="10"></textarea> <select name="" id=""></select>
单选框—radio
<div id="app"> <label> 男 <!-- 使用v-model 把input的name属性绑起来 --> <input type="radio" value="male" v-model="sex"> </label> <label> 女 <input type="radio" value="female" v-model="sex"> </label> {{sex}} <!-- <textarea name="" id="" cols="30" rows="10"></textarea> <select name="" id=""></select> --> </div>
复选框checkbox
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 方法存储在这里 data: { // 多选是要改为数组 sex: [] } })
<label> 男 <!-- 使用v-model 把input的name属性绑起来 --> <input type="checkbox" value="male" v-model="sex"> </label> <label> 女 <input type="checkbox" value="female" v-model="sex"> </label> {{sex}}
文本域
<textarea v-model="article" id="" cols="30" rows="10"></textarea>
下拉菜单
// 可以根据输入进去的数字来确定显示哪一个值, name: '1', dest: [],
<!-- 单选 --> <div>你来指哪里</div> <select v-model="name"> <option value="1">你</option> <option value="2">好</option> <option value="3">啊</option> <option value="4">你哦</option> </select> {{name}} <!-- 多选 --> <div>你来指哪里</div> <!-- 要可以多选就添加这个multiple --> <select v-model="dest" multiple> <option value="1">你</option> <option value="2">好</option> <option value="3">啊</option> <option value="4">你哦</option> </select> {{dest}} </div>
3. 值绑定
就是多选框,单选框,菜单里面供我们选择的值都是由后端传过来的,我们只需要把获取到的值进行遍历就行了
控制流指令
v-if v-else-if v-else
用于判断要不要渲染出来
true渲染
false不渲染
<!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>Document</title> </head> <body> <!--结合使用--> <div id="app"> <div v-if="role == '你好' || role == '不好'"> 你好 </div> <div v-else-if="role == '好'"> 好 </div> <div v-else> 你不配 </div> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
// 创建对象 var app = new Vue({ // 和哪一个元素绑定 el: '#app', // 方法存储在这里 data: { role: '你好' } })
v-show
与v-if非常相似
v-show 是把元素的display设置为none
v-if如果为false时压根不会有对应的DOM(使用一次时这个)
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>Document</title> </head> <body> <div id="app"> <table border="1"> <thead> <th>学科</th> <th>分数</th> </thead> <tbody> <tr> <td>数学</td> <td><input type="text" v-model.number="math"></td> </tr> <tr> <td>物理</td> <td><input type="text" v-model.number="physics"></td> </tr> <tr> <td>粤语</td> <td><input type="text" v-model.number="english"></td> </tr> <tr> <td>总分</td> <td>{{sum}}</td> </tr> <tr> <td>平均分</td> <td>{{average}}</td> </tr> </tbody> </table> </div> <script src="../lib/vue.js"></script> <script src="../js/main.js"></script> </body> </html>
// 计算属性 computed: { fullName: { set: function(newValue) { }, get: function() { return "ssss" } } } })
setter和getter属性
每一个计算属性都有:set方法一般不调用,如果要调用的话,是带有参数的
// 计算属性 computed: { fullName: { set: function() { }, get: function() { return "ssss" } } }
8. 组件化
将实例中template属性值进行编译,并将编译后的dom替换掉vue实例绑定的元素,如果该vue实例绑定的元素中存在内容,这些内容会直接被覆盖。
特点:1)如果vue实例中有template属性,会将该属性值进行编译,将编译后的虚拟dom直接替换掉vue实例绑定的元素(即el绑定的那个元素);
2)template属性中的dom结构只能有一个根元素,如果有多个根元素需要使用v-if、v-else、v-else-if设置成只显示其中一个根元素;
3)在该属性对应的属性值中可以使用vue实例data、methods中定义的数据。
template:"<div v-if='flag'>{{msg}}</div><div v-else>123</div>"//模板中只能有一个根元素,如果有多个需要使用v-if、v-else、v-else-if来选择显示哪一个
1. 思想
任何应用都会被抽象成也可组件树
有了组件化思想我们就可以将页面拆分为一个个小的、可复用得组件
2. 全局与局部
-
使用
-
- 创建组件构造器
- 注册组件
- 使用组件
-
-
这种方法写的就是全局组件
全局与局部:
全局:代表可以在多个Vue实例下面使用
局部:只能在一个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>Document</title> <style> a { color: #000; } </style> </head> <body> <div id="app"> <alert></alert> </div> <script src="../lib/vue.js"></script> <script src="../js/组件.js"></script> </body> </html>
// 这是全局的写法 // Vue.component('alert', { // 用于写元素 // template: '<button @click="on_click">酷酷酷</button>', // methods: { // on_click: function() { // alert("yo") // } // } // }); // new Vue({ // el: '#app' // }) // 局部的写法(推荐) var Alert = { template: '<button @click="on_click">酷酷酷</button>', methods: { on_click: function() { alert("yo") } } }; new Vue({ el: '#app', components: { // 自定义组件的名称,如果是多个单词的需要用单引号括起来 alert: Alert } })
3. 配置组件
Vue.component('like', { template: '<button @click="toggle_like()">赞{{like_count}}</button>', // 定义组件里面的data的值是要是个函数 data: function() { return { like_count: 10, liked: false, } }, methods: { toggle_like: function() { if (!this.liked) { this.like_count++; } else { this.like_count--; } this.liked = !this.liked; } } }) new Vue({ el: '#app' })
<!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>Document</title> </head> <body> <div id="app"> <like></like> </div> <script src="../lib/vue.js"></script> <script src="../js/组件配置.js"></script> </body> </html>
3.父组件和子组件
子组件中的模板必须存在div
父组件的components是用来声明子组件的,父组件要引入子组件
通信
Vue实例和组件,互为父子关系
组件和组件也可以互为父子关系
1. 父子组件通信
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 “prop”
基础:
<body> <div id="app"> <cpn v-bind:abc="mag"></cpn> </div> <template id="cpn"> <div> {{abc}} </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template: '#cpn', props: ['abc'] } const app = new Vue({ el: '#app', data: { mag: "你好" }, components: { cpn } }) </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>Document</title> </head> <body> <div id="app"> <!-- 定义一个键值对向子组件传值 --> <!-- <alert msg='yyy'></alert> --> <!-- 动态向子组件传值 --> <users usersname="www"></users> </div> <script src="../lib/vue.js"></script> <script src="../js/父子组件通信.js"></script> </body> </html>
// Vue.component('alert', { // // 用于写元素 // template: '<button @click="on_click">酷酷酷</button>', // // 用于通信, // props: ['msg'], // methods: { // on_click: function() { // alert(this.msg) // } // } // }); Vue.component('users', { // 用于写元素 template: '<a :href="\'/users/\' + usersname"> {{usersname}}</a>', // 用于通信 props: ['usersname'], methods: {} }); new Vue({ el: '#app' })
使用对象写法时,可以进行数据验证
<body> <div id="app"> <cpn v-bind:abc="mag"></cpn> </div> <template id="cpn"> <div> {{abc}} </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template: '#cpn', // 数组写法 // props: ['abc'] // 对象写法 props: { // 1. 类型限制 // abc: Array, 数组类型 // abc: String // 2. 提供默认值 abc: { type: String, default: '错误', // 代表必须传这个值abc required: true } } } const app = new Vue({ el: '#app', data: { mag: "你好" }, components: { cpn } }) </script> </body>
尽量不要使用驼峰命名法
如果使用了驼峰命名法时,在v-bing:时要把大写改小写之间用-连接
2. 子父组件通信
子组件通过事件向父组件通信
- 使用
$on(eventName)
监听事件- 使用
$emit(eventName)
触发事件
加不加括号,其实就是是否默认传事件对象 event 。不加括号时,函数第一个参数为 event,加了括号后,需要手动传入 $event 才能获得事件对象。
<body> <!-- 父组件模板 监听--> <div id="app"> <cpn v-on:item-click="cpnClick"></cpn> </div> <!-- 子组件模板 发射 --> <template id="cpn"> <div> <button v-for="item in categories" :key="item.id" @click="btnClick(item)"> {{item.name}} </button> </div> </template> <script src="../js/vue.js"></script> <script> // 子组件 const cpn = { template: '#cpn', data() { return { categories: [{ id: 'aaa', name: '热门推荐' }, { id: 'bbb', name: '手机数码' }, { id: 'ccc', name: '家用电器' }, { id: 'ddd', name: '家用办公' }, ] } }, methods: { btnClick(item) { // 发射事件 括号写事件名称 然后可以跟随参数 this.$emit('item-click') console.log(item) }, } } // 父组件 const app = new Vue({ el: '#app', data: { mag: "你好" }, components: { cpn }, methods: { cpnClick() { console.log('cpn') } } }) </script> </body>
如果需要传参数的的话只需要在emit里面带上参数,在父组件的methods的方法里面写上参数,那么系统就会默认传递过来,在其他元素
时就是传递event
对象
父子-子父加上input的双向绑定:可以了解一些
3. 任意及平行组件通信
任意间的通信需要时借助事件调渡器var Event = new Vue(),
注意,调度器必须写在mounted之前,其实就是调度器声明赋值要写在调度器使用前。
mounted表示组件挂载完毕的时候,初始化完毕是。可以在这监听看看其他组件说了什么。
mounted也叫生命周期的钩子,可以理解为生命周期里的一些关键节点,就像关键帧 里程碑一样。
// 使用调度器来实现任意及平行组件的通信 var Event = new Vue(); Vue.component('wanhuahau', { template: `<div> 我说:<input @keyup="on_said" v-model="i_said"/> </div>`, methods: { // emit这个方法用于完成事件的调度 on_said: function() { // 第一个参数为事件名称,第二个数据用于传数据 Event.$emit('huahua', this.i_said); } }, data: function() { return { i_said: '' } } }); Vue.component('xiaopan', { template: `<div> 花花说:{{huahua_said}} </div>`, data: function() { return { huahua_said: '', }; }, // 用于监听 mounted: function() { // 先把this赋值给me,因为后面这个this是代表Event var me = this; // 第一个参数为要监听的事件名称,第二个为函数,括号里面的参数用于接收调度器传过来的数据 Event.$on('huahua', function(a) { me.huahua_said = a; }); }, }) new Vue({ el: '#app', })
<!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>Document</title> </head> <body> <div id="app"> <wanhuahau></wanhuahau> <xiaopan></xiaopan> </div> <script src="../lib/vue.js"></script> <script src="../js/任意及平行通信.js"></script> </body> </html>
4. 父子组件的访问方式
1. 父访问子
使用
$
children或$refs
children里面包含了子组件的全部属性、方法
父组件通过这个方法来调用子组件的方法和属性
<body> <template id="cpn"> <div> <h1>我是子组件</h1> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { mag: '你好' }, methods: { btnClick() { console.log(this.$children); this.$children[0].showMessage() } }, components: { cpn: { template: '#cpn', methods: { showMessage() { console.log("showMessage") } } } } }) </script> </body>
refs:默认是空对象
使用时要在组件上加上ref=“名字”,来当作标识,这样打印出来的才有值,我们取得名字就是key,然后就可以通过this.$refs.aa来获取我们需要的子组件
<body> <template id="cpn"> <div> <h1>我是子组件</h1> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { mag: '你好' }, methods: { btnClick() { console.log(this.$refs.aa); this.$refs.aa.showMessage } }, components: { cpn: { template: '#cpn', methods: { showMessage() { console.log("showMessage") } } } } }) </script> </body>
2. 子访问父
使用$parent
开发中不建议使用,因为我们小组件不应该这样做,小组件只需要收/传一些数据就行,如果可以访问父,那么复用性就不行了,耦合性高
<body> <template id="cpn"> <div> <h1>我是子组件</h1> <button @click="btnClick">按钮</button> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { mag: '你好' }, methods: { }, components: { cpn: { template: '#cpn', methods: { btnClick() { console.log(this.$parent); console.log(this.$parent.mag); } } } } }) </script> </body>
直接访问根组件$root
4. 模板抽离写法
第一种:类型必须为text/x-template
<div id="app"> <my-cpn></my-cpn> </div> <!-- 第一种写法 --> <script type="text/x-template" id="cpn"> <div> <h2>你好</h2> </div> </script> <script src="../js/vue.js"></script> <script> // 1. 创建组件构造器对象 需要传入对象 const cpn = Vue.extend({ template: '#cpn' }); // 2. 注册组件 第一次参数是组件的名字 第二个是组件构造器的名字 Vue.component('my-cpn', cpn); const app = new Vue({ el: "#app", data: { msg: "hello" } }) </script>
第二种:
<!-- 第二种写法 --> <template id="cpn"> <div> <h2>你好</h2> </div> </template> <script src="../js/vue.js"></script> <script> // 1. 创建组件构造器对象 需要传入对象 const cpn = Vue.extend({ template: '#cpn' }); // 2. 注册组件 第一次参数是组件的名字 第二个是组件构造器的名字 Vue.component('my-cpn', cpn); const app = new Vue({ el: "#app", data: { msg: "hello" } }) </script>
5. 组件访问data数据
组件是不能直接访问Vue实例里面的数据的
组件有自己保存数据的地方
data:这个不是个对象,而是一个函数,而且还是需要返回值的
也有methods属性
为什么必须是函数?
防止使用多次同一个组件时,资源造成共享,使用函数时每次调用就会插件一个新的对象,这样就不会造成资源共享
9. 过滤器
通过|符号把前面的数据传到后面的过滤器里面
// 用来定义过滤器,第一个参数为过滤器名称,第二个为一个函数,括号里面写传参名称就好,具体的值系统会传过来 Vue.filter('currency', function(val, unit) { // 进行判断赋值 val = val || 0; unit = unit || '元'; return val + unit; }) Vue.filter('meter', function(val, unit) { // 进行判断赋值 val = val || 0; unit = unit || 'm'; // toFixed表示小数点后几位 return (val / 1000).toFixed(2) + unit; }) new Vue({ el: '#app', data: { price: 10, length: 1 } })
<!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>Document</title> </head> <body> <div id="app"> <div> <input type="text" v-model="length"> {{length | meter(m)}} </div> <!-- js定义参数,过滤器传进去 --> <input type="text" v-model="price"> {{price | currency('hhh')}} </div> <script src="../lib/vue.js"></script> <script src="../js/过滤器.js"></script> </body> </html>
另外一种写法
<div id="app"> <div>{{第一个为要传进去的参数|这个为过滤器的名称}}</div> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', filters: { show(aa){ return ; } } }) </script>
10. 自定义指令
有全局的也有局部的,同时还有钩子
基础配置
// 定义指令 第一个参数自定义指令名称,第二个为函数,括号里面第一个为系统传过来的元素,第二个为指令的值 Vue.directive('pin', function(val, unit) { var pinned = unit.value; if (pinned) { val.style.position = 'fixed' } else { val.style.position = 'static' } }) new Vue({ el: '#app', data: { // 这样写的话,外面引用就要用card1.pinned这样的格式 card1: { pinned: true } } })
<!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>Document</title> <style> .a { width: 200px; margin: 5px; background: #ccc; padding: 10px; } </style> </head> <body> <div id="app"> <div v-pin="card1.pinned" class="a"> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Error quisquam laudantium fuga, natus quis reprehenderit deleniti minus eum cumque ab sequi id qui molestiae fugiat, eligendi, commodi officiis distinctio illum. <button @click="card1.pinned = !card1.pinned">点击</button> </div> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? </div> <script src="../lib/vue.js"></script> <script src="../js/自定义指令.js"></script> </body> </html>
配置传参及修饰
// 定义指令 第一个参数自定义指令名称,第二个为函数,括号里面第一个为系统传过来的元素,第二个为指令的值 Vue.directive('pin', function(val, unit) { // 获取值 var pinned = unit.value; // 通过第二个传参来获取修饰符 var position = unit.modifiers // 获取传参的值 var warning = unit.arg if (pinned) { val.style.position = 'fixed' for (var key in position) { if (position[key]) { val.style[key] = '100px' } } } else { val.style.position = 'static' } if (warning === 'true') { val.style.background = 'yellow' } }) new Vue({ el: '#app', data: { // 这样写的话,外面引用就要用card1.pinned这样的格式 card1: { pinned: true } } })
<!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>Document</title> <style> .a { width: 200px; margin: 5px; background: #ccc; padding: 10px; } </style> </head> <body> <div id="app"> <!-- 给自定义指令添加修饰符,同时在js里面获取到 --> <!-- v-pin:为传参 --> <div v-pin:true.bottom.right="card1.pinned" class="a"> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Error quisquam laudantium fuga, natus quis reprehenderit deleniti minus eum cumque ab sequi id qui molestiae fugiat, eligendi, commodi officiis distinctio illum. <button @click="card1.pinned = !card1.pinned">点击</button> </div> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit veniam blanditiis soluta aspernatur saepe distinctio at! Ut libero adipisci in inventore ab officiis laboriosam. Unde est minima atque exercitationem officiis? </div> <script src="../lib/vue.js"></script> <script src="../js/自定义指令.js"></script> </body> </html>
11. mixinx混合
定义了一部分可复用的方法或者计算属性。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
如果 methods 选项中有相同的函数名,则 Vue 实例优先级会较高。会把mixinx的覆盖掉
如果使用了全局那么就会影响到所有Vue实例
var base = { methods: { show: function() { this.visible = !this.visible }, hide: function() { this.visible = !this.visible }, toggle: function() { this.visible = !this.visible } }, data: function() { return { visible: false } }, } Vue.component('tooltip', { template: `<div> <span @mouseenter="show" @mouseleave="hide">hh</span> <div v-if="visible">哈哈</div> </div>`, // 使用混合,数组形态,系统会自动调用 mixins: [base] }) Vue.component('popup', { template: ` <div> <button @click="toggle">poput</button> <div v-if="visible"> sdfghjklytrewertyuiojhgvbnm,mnbvcvbnm </div> </div>`, mixins: [base] }) new Vue({ el: '#app', })
<!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>Document</title> </head> <body> <div id="app"> <popup></popup> <tooltip></tooltip> </div> <script src="../lib/vue.js"></script> <script src="../js/mixinx混合.js"></script> </body> </html>
12. slots 插槽
使组件拥有扩展性,而不是直接写死
而slot就是给组件预留了空间,在要使用的时候调用就行
具名插槽:就是带name的
如果只有一个插槽,而插入的元素很多,那么会默认全部替换
Vue.component('aa', { template: '#a' }) new Vue({ el: '#app', })
<!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>Document</title> </head> <body> <div id="app"> <aa> <!-- slot=要插入的那个插槽的name,这样就可以把内容插入到那一个插槽 --> <div slot="header"> neir </div> <div slot="body"> 哈哈 </div> <div slot="fooder"> jj </div> </aa> </div> <template id="a"> <div> <div> <!-- 添加插槽 使用name属性可以在使用时指定插入那一个插槽--> <slot name="header"></slot> </div> <div> <slot name="body"></slot> </div> <div> <!-- 如果要有默认值就直接在这个模板写就行 --> <slot name="fooder">jj</slot> </div> </div> </template> <script src="../lib/vue.js"></script> <script src="../js/插槽.js"></script> </body> </html>
编译作用域
父组件模板中的内容对应在VUE实例中——》父组件模板作用域就是VUE实例
子组件模板中的内容对应在子组件中——》子组件模板作用域就是子组件中
作用域插槽
父组件替换插槽的标签,但是内容由子组件来提供
<body> <template id="cpn"> <div> <!-- 使用插槽的data属性 让父组件可以获取到子组件的值 --> <!-- 把pLanguages的值传给data --> <slot :data="pLanguages"> <ul> <li v-for="item in pLanguages" :key="item.id"> {{ item }} </li> </ul> </slot> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { mag: '你好' }, methods: { }, components: { cpn: { template: '#cpn', data() { return { pLanguages: ['JavaScript', 'Java', 'C++', 'python', 'go'] } } } } }) </script> </body>
13. 路由
是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。
router-view路由匹配到的组件将渲染在这里
基本配置及入门
// 定义路由 var routes = [{ path: '/', component: { template: ` <div><h1>登录</h1></div> `, }, }, { path: '/hh', component: { template: ` <div><h1>注册</h1></div> `, }, } ] // 把定义好的路由传过来 const router = new VueRouter({ routes: routes, }); new Vue({ el: '#app', // 把router传来 router: router, })
<!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>Document</title> </head> <div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 组件来导航. --> <!-- 通过传入 `to` 属性指定链接. --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --> <router-link to="/">Go to Foo</router-link> <router-link to="/hh">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> <script src="../lib/vue.js"></script> <script src="../lib/路由.js"></script> <script src="../js/路由.js"></script> <body> </body> </html>
E:\htmldaima\vue\lib\路由.js
传参
会获取到右边的名字
可以通过 ?的形式获取东西
子路由
append
设置 append 属性后,则在当前 (相对) 路径前添加其路径
// 定义路由 var routes = [{ path: '/', component: { template: ` <div><h1>登录</h1></div> `, }, }, { path: '/hh/:name', component: { // 在这里调用子路由 template: ` <div> <div><h1>{{$route.params.name}}</h1></div> <router-link to="more" append>更多信息</router-link> <router-view></router-view> </div>`, }, // 子路由 用于追加东西 children: [{ path: 'more', component: { // 子路由 可以使用父级路由的东西 template: ` <div> {{$route.params.name}}看看看看 </div> ` } }] } ] // 把定义好的路由传过来 const router = new VueRouter({ routes: routes, }); new Vue({ el: '#app', // 把router传来 router: router, })
html没改变
14. 解惑
为什么切换另一个input标签时,第一个input标签的内容会在第二个标签里面显示?
这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已有的元素,而不会重新创建新的元素
解决方法:
如果不重复使用,可以给对应的input添加key
并且要保住key的不同,如果key的值一样的话就代表要复用
<input type="text" key="aa">
15. 模块化
就是把系统分成各个独立的部分,每个部分单独实现功能,将系统分割成可独立的功能部分。
没有使用模块化会导致命名重复等不必要的麻烦问题
随着MVC等框架、微服务等技术的兴起,模块化开发已经称为必须。web前端也已经演变称为大前端。
优点:
可维护性高
- 架构清晰,灵活开发
- 降低程序耦合性
- 方便模块功能调试、升级以及模块间的组合分解
缺点:
损耗性能
- 系统分层,调用链长
- 模块间通信发送消息很消耗性能
模块化规范
核心–导入–导出
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】