基于vue2的指令、监听、过滤器等基础知识
1.认识Vue
原因:用原生直接操作dom节点每次操作都导致页面重新渲染,如果操作频繁就会使页面频繁的被渲染,频繁卡顿,效率低
Vu是一套用于构建用户界面的渐进式框架。
与其他大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅容易上手,还便于与第三方库或既有项目整合。
Vue框架涉及的内容有:Vue.js开发概述、环境搭建、Vue指令、组件化应用构建、组件通信、组件嵌套、自定义指令、自定义过滤器、组件属性、组件的路由、路由跳转。
注意:Vue不支持IE8以下版本。
1.1vue.js是MVVM开发模式
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View代表UI组件,它负责将数据模型转化成UI展现出来,ViewModel是一个同步View和Model的对象
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
1.2vue框架的特点
-
组件开发,提高代码的复用率
-
声明式编程(更多的关注数据),以前是命令式编程,不再操作复杂的DOM树
-
虚拟DOM
在Vue.js中,我们使用模板来描述状态与DOM之间的映射关系,Vue.js通过编译模板转换成渲染函数(render),执行渲染函数(render)就可以得到一个虚拟节点树,使用这个虚拟节点树就可以渲染页面。
模板-------->渲染函数----------->vnode---------->视图(页面)
vnode:是虚拟节点,是计算机内存中生成的,效率高;短时间重复修改data执行效率依旧很高
虚拟DOM的最终目标是将虚拟节点(vnode)渲染到视图上。但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的DOM操作。
为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点做对比,找出真正需要更新的节点来进行DOM操作,从而避免操作其他无任何改动的DOM。
1.提供与真实DOM节点所对应的虚拟节点vnode
2.将虚拟节点vnode和旧虚拟节点oldVnode进行对比,如何更新视图。
2.环境搭建
2.1、直接用<script>
引入
直接下载vue.js文件,并用<script>
标签引入
<script src=”c:/vue/2.6.14/vue.min.js” />
2.1、cdn
<script src=”https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js” />
2.3、npm
在用 Vue 构建大型应用时推荐使用 NPM 安装。NPM 能很好地和诸如 webpack 或 Browserify 模块打包器配合使用。同时 Vue 也提供配套工具来开发单文件组件。
npm i vue
2.4、命令行工具(cli)
Vue 提供一个官方命令行工具,可用于快速搭建大型单页应用。该工具为现代化的前端开发工作流提供了开箱即用的构建配置。只需几分钟即可创建并启动一个带热重载、保存时静态检查以及可用于生产环境的构建配置的项目:
# 全局安装 vue-cli
$ npm i -g @vue/cli
# 创建一个基于 webpack 模板的新项目
$ vue create my-project
# 进入项目目录, 启动服务,走你
$ cd my-project
$ npm run serve
以上四种vue的引入方式只需采用其一即可。
3.Vue指令
模板语法
Vue.js使用了基本HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。
Vue.js的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进DOM的系统。
结合响应系统,在应用状态改变时,vue能够智能地计算出重新渲染组件的最小代价并应用到DOM操作上。
3.1数据绑定(插值)
- { {…}} (双大括号)文本插值, 用于输出数据到元素内容
语法:<div>{
{表达式}}</div>
-
v-bind:绑定数据到标签的属性,可以简写为 : (冒号)
语法:
<div v-bind:id=”表达式”></div>
<h2 :style="{ color: color }" :title="title" id="big"> { {title}} </h2>
在vue实例的外面获取实例中定义的数据
vm.title
vm.$data.title
在vue实例的外面修改实例中定义的数据
vm.title = ‘表达式’
示 例:
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 挂载节点 -->
<div id="app">
<!-- {
{}} 插值表达式, 用来绑定数据到标签内容区 -->
<h2> {
{title}} </h2>
<!-- v-bind: 绑定数据到 标签的属性, 可以简写为 : -->
<h2 :style="{ color: color }" :title="title" id="big"> {
{title}} </h2>
<h2> {
{count}} </h2>
</div>
<script src="./vue-2.5.21.js"></script>
<script src="./index.js"></script>
</body>
</html>
js文件
// 由于 vue-2.5.21.js 文件( vue的核心库文件 ) 对外暴露了Vue函数, 所以就可以直接使用Vue函数实例化对象
//实例化Vue对象, 并挂载对象到app节点
var vm = new Vue({
el: '#app',
data: {
//data 负责定义数据, 内部定义的数据都是响应式数据, 数据会自动添加在Vue实例对象身上.
title: '今天开始学习vuejs',
count: 888,
color: 'red'
}
})
// 在Vue实例的外面 获取实例中定义的数据
// vm.title
// vm.$data.title
// 在Vue实例的外面 修改实例中定义的数据, 修改响应式数据的同时,任何绑定了该数据的地方都会自动更新(程序员只需要提前绑定数据到页面, 操作数据就可以了,页面的更新交给vuejs完成).
// vm.title = 'vuejs'
3.2列表渲染
v-for
可以根据数组、对象来渲染列表
语法:
<div v-for=”(item,index) in数组” :key=”index”>
{ {item}}
</div>
案例1:
html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
span {
padding: 5px 10px;
background-color: #aaa;
margin-right: 10px;
margin-bottom: 5px;
display: inline-block;
border-radius: 10px;
}
</style>
</head>
<body>
<div id="app">
<!-- v-for 列表渲染, item 是数组元素, index 是元素下标 -->
<!-- v-for="(item,index) in 数组" -->
<span v-for="(item,index) in arr">{
{item}}</span>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="index-列表渲染.js"></script>
js文件:
var vm = new Vue({
el: '#app',
data: {
//负责定义数据
arr: ['麻辣烫', '米线', '披萨', '蛋糕', '汉堡', '腊八粥', '烤肉拌饭', '炸鸡', '味多美']
}
});
案例2:
html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
display: flex;
flex-wrap: wrap;
}
.block {
width: 20%;
text-align: center;
font-size: 12px;
margin-bottom: 10px;
}
.block img {
width: 60%;
margin-bottom: 10px;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="app">
<div class="block" v-for="(item,index) in arr">
<img v-bind:src="item.pic" alt="">
<div class="name">{
{item.name}}</div>
</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="index-列表渲染2.js"></script>
js文件
var picUrl = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202107%2F23%2F20210723125859_f6b2f.thumb.1000_0.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1668062633&t=127aac56735411349eab6ddb49fd8cce';
var vm = new Vue({
el: '#app',
data: {
arr: [
{
pic: picUrl, name: '护肤' },
{
pic: picUrl, name: '彩妆' },
{
pic: picUrl, name: '香氛' },
{
pic: picUrl, name: '进口酒' },
{
pic: picUrl, name: '国产酒' },
{
pic: picUrl, name: '精品奢货' },
{
pic: picUrl, name: '食品百货' },
{
pic: picUrl, name: '母婴专区' },
{
pic: picUrl, name: '直播专区' },
{
pic: picUrl, name: '特卖专场' }
]
}
})
3.3事件处理
v-on 用于给目标元素绑定事件,可以绑定元素支持的任何事件
语法: <div v-on:事件类型=”js代码”></div>
如果事件触发时需要执行的js代码很多, 可以将js代码写入到一个js函数中, 事件触发时调用该函数即可.
语法: <div v-on:事件类型=”函数名”></div>
如果事件触发时,调用函数并且需要传参,可以这样写:
语法: <div v-on:事件类型=”函数名(参数)”></div>
案例:
点击哪个标签中的领取按钮时当前标签中的按钮可变为去使用
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
display: flex;
flex-wrap: wrap;
padding: 10px;
font-size: 12px;
justify-content: space-between;
align-items: center;
}
.card {
width: 30%;
background-color: #f5f5f5;
margin-bottom: 10px;
text-align: center;
line-height: 40px;
}
</style>
</head>
<body>
<div id="app">
<div class="card" v-for="(item,index) in arr">
<div class="price">¥{
{item.price}}</div>
<div class="title">{
{item.title}}</div>
<div class="cond">满{
{item.cond}}元可用</div>
<!-- v-on: 事件绑定 , 可以简写为 @ -->
<!-- v-on:事件类型="js代码" js代码的位置可以放置一个函数,或 函数调用, 调用时可以向函数内部传参 -->
<!-- <button v-on:click="lingqu(item,index)">{
{item.lq?'去使用':'领取'}}</button> -->
<button @click="lingqu(item,index)">{
{item.lq?'去使用':'领取'}}</button>
</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="index-列表渲染3.js"></script>
js文件
var vm = new Vue({
el: '#app',
data: {
arr: [
{
title: '大型超市外送', price: 6, cond: 8, lq: false },
{
title: '吃货红包', price: 3, cond: 6, lq: false },
{
title: '买药红包', price: 3, cond: 8, lq: false },
{
title: '水果外送红包', price: 7, cond: 10, lq: false },
{
title: '吃货红包', price: 6, cond: 6, lq: false },
{
title: '吃货红包', price: 5, cond: 10, lq: false },
]
},
methods: {
//负责定义函数,多个函数用逗号分割
// lingqu:function(){
// }
lingqu(item, index) {
// 修改当前点击红包对象的lq属性的值,改为true
item.lq = true;
// 在函数(方法)中,使用this,this是当前Vue实例对象
console.log(this.arr);
}
}
})
3.4表单输入
v-model 用于绑定表单内容到变量, v-model是”双向数据绑定”指令( 当用户操作表单元素时,元素的值会自动保存到绑定的变量中, 当变量的值发生改变时会自动显示到表单元素中 )
语法: <input v-model=”变量”></input>
案例
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
margin: 10px 5px;
}
.searchbox {
display: flex;
align-items: center;
}
.searchbox input {
height: 40px;
border: 0px;
outline: none;
background-color: #f5f5f5;
padding-left: 20px;
color: #999;
font-size: 14px;
flex: 1;
border-radius: 20px;
}
.searchbox span {
width: 40px;
text-align: center;
}
.block {
margin: 10px;
}
.block .title {
font-weight: bold;
padding: 10px 0;
}
.block .list span {
display: inline-block;
background-color: #f5f5f5;
padding: 5px 10px;
border-radius: 5px;
margin-right: 10px;
}
</style>
</head>
<body>
<div id="app">
<div class="searchbox">
<!-- v-model 表单数据绑定, 也是唯一一个具有双向数据绑定特点的指令 -->
<!-- v-model 指令主要配合表单元素使用 -->
<input type="text" placeholder="输入关键字" v-model="searchText">
<span @click="search">搜索</span>
</div>
<div class="block">
<div class="title">历史搜索</div>
<div class="list">
<span v-for="(item,index) in searchArr">{
{item}}</span>
</div>
</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="输入框的绑定.js"></script>
js文件
var vm = new Vue({
el: '#app',
data: {
//负责定义响应式数据
searchText: '',//保存输入框输入的内容(临时)
searchArr: [
'三文鱼', '慈善', '与'
]
},
methods: {
//负责定义方法(函数)
search() {
if (this.searchText) {
// 将输入框中输入的内容 保存到searchArr中
this.searchArr.push(this.searchText);
// 清空输入框
this.searchText = '';
}
}
}
})
3.5登录案例
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
margin: 50px;
}
.title {
font-weight: bold;
margin: 50px 0;
text-align: center;
font-size: 20px;
}
.block {
margin: 50px 0;
}
.block input {
height: 40px;
width: 100%;
border: none;
outline: none;
background-color: #f5f5f5;
padding-left: 20px;
border-radius: 20px;
box-sizing: border-box;
}
</style>
</head>
<body>
<div id="app">
<div class="title">登录页</div>
<div class="block">
<input type="text" placeholder="账号" v-model="id">
</div>
<div class="block">
<input type="password" placeholder="密码" v-model="pwd">
</div>
<div class="block">
<input type="button" value="登陆" @click="login">
</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="登录.js"></script>
js文件
var vm = new Vum({
el: '#app',
data: {
id: '',
pwd: ''
},
methods: {
login() {
console.log(this.id, this.pass);
// 获取到输入的账号,密码,发请求
// 。。。
// 可以随时清空输入框的值
this.phone = '';
this.pass = ''
}
}
})
3.6购物车
条件渲染
v-if 条件成立时,渲染元素,否则不渲染
v-else 条件不成立时,渲染元素
v-else-if
v-show 条件成立时,显示元素否则不显示
注意:
- v-if , v-else 条件渲染指令 用来控制标签的显示/隐藏, 他俩必须放置在两个兄弟标签上, 条件成立时渲染该标签, 条件不成立不渲染标签
- v-if 和 v-for 放在同一个标签上时, v-for的优先级更高, v-if就会失效, 需要避免这样的用法
- v-show 通过条件控制标签的显示隐藏, 本质上是通过控制标签的css样式display 实现标签的显示/隐藏
- v-show 无论条件是否成立, 标签肯定会渲染
数据绑定
v-html 指令用于输出数据到元素内容(可以解析标签)。
语法: <div v-html=”表达式”></div>
v-text 指令用于输出数据到元素内容(无法解析标签)。
语法: <div v-text=”表达式”></div>
注意
- v-html , v-text 都可以绑定数据到标签内容 和 { {}} 的作用一样
- v-html 可以解析标签
- v-text 无法解析标签
- { {}}无法解析标签
列表渲染
v-for v-for可以根据数组、对象来渲染列表
语法:
<div v-for=”(item,index) in数组” :key=”index”>
{
{item}}
</div>
解释: v-for指令放在哪个元素上, 就会根据数组的长度n最终渲染出n个元素,包括内部的子元素, 形成一个列表, 通过key属性给渲染出来的每个列表元素绑定一个唯一索引, 避免vue的警告。
key属性的作用
key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;如果不使用key,vue会使用一种最大限度减少动态元素并且尽可能尝试就地修改/复用相同类型元素的算法;而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素
在进行插入或者重置顺序时,使用key属性可以让diff算法更高效,提高渲染效率
v-pre
让标签内容原样显示,而不是先编译后显示
<h1 v-pre>{
{msg}}</h1>
<h1 v-pre>{
{1+1}}</h1>
v-once
作用:让元素/组件只渲染一次,为了避免无效的更新
元素只渲染一次,当页面运行的时候将msg渲染到页面当点击后msg会变但是不会再次渲染到页面
<h1 v-once @click="msg=888">{
{msg}}</h1>
data(){
return {
msg:'Vuejs项目'
}
}
v-cloak
避免元素在渲染结束前显示双大括号
解决将渲染结束后的结果渲染到页面上,双大括号不会出现
<h1 v-cloak>{
{msg}}</h1>
data(){
return {
msg:'Vuejs项目'
}
}
3.7数组排序
mysort(index){
if( index == 0 ){
//点击了第一个按钮
this.list.sort((a,b)=>{
return a.price - b.price;
})
}
else if( index == 2 ){
//点击了第三个按钮
this.list.sort((a,b)=>{
return b.count - a.count;
})
}
}
案例:
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
}
#app {
height: 100%;
position: relative;
background-color: rgba(0, 0, 0, .3);
}
.shopcart {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
padding: 15px;
padding-bottom: 80px;
background-color: white;
}
.shopcart .title {
display: flex;
justify-content: space-between;
}
.shopcart .title span:nth-child(1) {
font-weight: bold;
}
.shopcart .list .good {
display: flex;
margin: 10px 0;
}
.shopcart .list .good .imgbox {
width: 80px;
margin-right: 10px;
}
.shopcart .list .good .imgbox img {
width: 100%;
}
.shopcart .list .good .text {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.shopcart .list .good .text .name {
font-weight: bold;
}
.shopcart .list .good .text .price {
display: flex;
justify-content: space-between;
}
.shopcart .list .good .text .price span {
display: inline-block;
width: 14px;
height: 14px;
text-align: center;
line-height: 14px;
background-color: lightskyblue;
border-radius: 50%;
color: white;
}
.shopcart .list .good .text .price span:nth-child(2) {
color: black;
background-color: white;
}
.empty {
text-align: center;
padding: 50px;
}
.shopcart .btns {
display: flex;
justify-content: space-between;
}
</style>
</head>
<body>
<div id="app">
<div class="shopcart">
<div class="btns">
<span @click="sort(index)" v-for="(item,index) in btnArr" :key="index">{
{item}}</span>
</div>
<div class="list" v-if="list.length !=0">
<div class="good" v-for="(item,index) in list" :key="index">
<div class="imgbox">
<img :src="item.pic" alt="">
</div>
<div class="text">
<div class="name">{
{item.name}}</div>
<div class="price">
<div class="lift">¥{
{item.price}}</div>
<div class="right">
<span @click="sub(item)">-</span>
<span>{
{item.count}}</span>
<span @click="add(item)">+</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="02、数组排序.js"></script>
js文件
var pic = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202105%2F04%2F20210504062111_d8dc3.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1668131448&t=6f7b1534d0d276bbfdad97cdf85700e6'
var vm = new Vue({
el: '#app',
data: {
//负责定义响应式数据
btnArr: ['综合排序', '距离最近', '销量最高', '筛选'],
list: [
{
name: '秋刀鱼', price: 88, pic, count: 1 },
{
name: '大黄鱼', price: 777, pic, count: 2 },
{
name: '皮皮虾', price: 9, pic, count: 3 },
]
},
methods: {
//负责定义方法
// 点击+号时物品数量+1
add(item) {
item.count++;
},
// 点击-号时物品数量-1
sub(item) {
// 最小是1
if (item.count > 1) item.count--;
},
// 当点击清空时物品清空
clear() {
this.list = [];
},
sort(index) {
if (index == 0) {
//点击了第一个按钮
this.list.sort((a, b) => {
return a.price - b.price;
})
}
else if (index == 2) {
//点击了第三个按钮
this.list.sort((a, b) => {
return b.count - a.count;
})
}
}
},
})
3.8数组变化
组件更新检测
Vue 包含一组观察数组的变异方法,它们也将会触发视图更新。这些方法如下:
push() pop() shift() unshift() splice() sort() reverse()
注意事项:
由于JavaScript的限制,Vue不能检测以下变动的数组:
1.当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
2.当你修改数组的长度时,例如:vm.items.length = newLength
>
Vue提供的方法
1.Vue.set(vm.items, indexOfItem, newValue)
例如:Vue.set(this.arr,2,'cc');
2.vm.$set(vm.items, indexOfItem, newValue)
例如:this.$set(this.arr,2,'cc')
案例:
html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="" id="app">
<button @click="add">添加元素</button>
<div style="color: red;" v-for="(item,index) in arr">{
{item}}</div>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="03、数组变化.js"></script>
js文件:
var vm = new Vue({
el: '#app',
data: {
arr: ['aa', 'bb']
},
methods: {
add() {
//用这样的方式 给数组添加新元素, Vue无法检测到数组的变化, 导致页面无法自动更新
//this.arr[2] = 'cc';
//Vue提供的工具方法
// Vue.set(this.arr, 2 , 'cc');
this.$set(this.arr, 2, 'cc');
}
}
})
3.9选项
3.9.1 计算属性computed(负责定义计算属性)
计算的函数可以在普通函数中也可以在计算属性中定义,而计算属性中定义又有两种写法一种是回调函数一种是setter&getter ;普通函数用的时候要以函数调用的形式用,在计算属性中定义的函数当变量用。
当程序中需要在页面显示的数据不是固定的,而是需要动态计算得出时,可以考虑使用 computed ( 一个组件只能写一个computed, 但是可以在computed内用逗号分割定义多个计算属性 )。
用法一:
回调函数写法,返回一个经过计算的新值, 并且这个新值会被缓存起来.
var vm = new Vue({
el: '#app',
data: {
firstname: 'Tom',
lastname: 'cat'
},
computed: {
fullname : function () {
return this.firstname + ' ' + this.lastname;
},
xxx : function (){
}
}
})
使用计算属性:
<div> {
{ fullname }} </div>
计算属性的特征:定义时像函数(方法),使用时像变量,计算属性会被缓存(多次使用同一个计算属性只会计算一次)
用法二:
setter&getter写法,在对象中添加 get 和 set 两个方法
当页面去获取fullname的时候呢,它就会触发get方法的执行.
当给fullname赋值的时候会触发 set 方法的执行,fullname并不可直接被修改,赋给 fullname的值会作为参数传递到 set 方法中
var vm = new Vue({
el: '#app',
data: {
firstname: 'Tom',
lastname: 'cat'
},
computed: {
fullname : {
get: function () {
return this.firstname + ' ' + this.lastname;
},
set: function (newStr) {
this.firstname = newStr.split(' ')[0];
this.lastname = newStr.split(' ')[1];
}
}
}
})
案例:
html文件:
<!-- 商品总数 -->
<div class="count">
<div class="countsum">
<!-- 普通函数时的写法 -->
<!-- <span>总数:{
{totalCount()}}</span>
<span>¥{
{totalPrice()}}</span> -->
<!-- 计算属性 -->
<span>总数:{
{zongshu}}</span>
<span>¥{
{zongjia}}</span>
</div>
<div class="jiesuan">
去结算
</div>
</div>
js文件:
var pic = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202105%2F04%2F20210504062111_d8dc3.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1668131448&t=6f7b1534d0d276bbfdad97cdf85700e6'
var vm = new Vue({
el: '#app',
data: {
//负责定义响应式数据
list: [
{
name: '秋刀鱼', price: 88, pic, count: 1 },
{
name: '大黄鱼', price: 777, pic, count: 2 },
{
name: '皮皮虾', price: 9, pic, count: 3 },
]
},
methods: {
//负责定义方法
// 点击+号时物品数量+1
add(item) {
// 最大是5
if (item.count < 5) item.count++;
},
// 点击-号时物品数量-1
sub(item) {
// 最小是1
if (item.count > 1) item.count--;
},
// 当点击清空时物品清空
clear() {
this.list = [];
},
// 当普通函数
// totalCount(){
// console.log('普通函数: totalCount 执行了');
// var sum = 0;
// this.list.forEach((item)=>{
// sum += item.count;
// })
// return sum;
// },
// totalPrice(){
// var sum = 0;
// this.list.forEach((item)=>{
// sum += item.count * item.price;
// })
// return sum;
// }
},
computed: {
//负责定义计算属性
// 1.计算属性在定义时像函数,使用时像只读变量
// 2.当计算属性内部所依赖的数据发生改变时,计算属性内部的代码会自动重新执行,计算出一个新值,这个新值作为计算属性的值
// 3.如果计算属性内部所依赖的数据未发生改变,则计算属性不会重新计算,而是使用第一次计算的缓存结果作为下一次使用的值(计算属性会缓存计算的结果)。
zongshu() {
var sum = 0;
this.list.forEach((item) => {
sum += item.count;
});
return sum;
},
// zongjia() {
// var sum = 0;
// this.list.forEach((item) => {
// sum += item.price * item.count;
// });
// return sum;
// }
// 写法二:setter&getter
zongjia: {
//get方法会在使用(渲染)计算属性时自动执行
get() {
var sum = 0;
this.list.forEach((item) => {
sum += item.count * item.price;
})
return sum;
},
set() {
//set方法会在给计算属性设置值时执行
console.log('给zongjia设置值');
}
}
}
})
3.9.2方法methods
在组件中需要定义自己的方法时, 这时使用 methods( 一个组件只能写一个methods, 但是可以在methods内用逗号分割定义多个方法 ) .
var vm = new Vue({
el: '#app',
data: {
message: 'Runoob!'
},
methods : {
login: function () {
alert(‘登陆成功!’)
},
xxx : function () {
}
}
})
使用方法: 一般配合事件使用
<div @click=”login”> 登陆 </div>
在这个例子中, login就是方法, 你可以在调用方法时给方法传参;
3.10选项中的监听
如果需要实时监听某个数据的改变, 这时使用watch( 一个组件只能写一个watch, 但是可以在watch内用逗号分割定义多个监听 )。
普通监听
export default {
data: {
message: 'Runoob!'
},
watch: {
message: function (newVal,oldVal) {
alert(‘监听到了改变’,newVal )
}
}
}
在这个例子中, 每当message的值发生改变时, 就会自动执行watch中message后面的方法, 在该方法中可以获取到message的最新值;
数组监听
export default {
data: {
arr: [1,2,3]
},
watch: {
arr: function (newVal,oldVal) {
alert(‘监听到了改变’,newVal )
}
}
}
对象监听
当使用watch监听的时候,我们可能会发现它可以监听某个数据【单数据,数组】,但是当监听对象的时候,明明数据修改了,却没有监听的提示,这是为什么呢?
这个时候,需要我们开启深度监控,因为在我们没有开启深度监控的时候,watch只会监听第一层,而对象的数据修改了,但对象它的首地址没有修改,所以watch判定它没有发生数据的变化,从而监听不到.
var vm = new Vue({
el: '#app',
data: {
obj: {
name: 'Runoob!',age:20 }
},
watch: {
obj: {
handler : function(){
alert('监听到改变!') },
immediate :true, //是否立即执行handler函数
deep: true
}
}
})
案例
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
padding: 20px 10px;
}
.inputbox input {
height: 40px;
border-radius: 20px;
padding-left: 20px;
width: 100%;
box-sizing: border-box;
background-color: #f5f5f5;
border: none;
outline: none;
margin-bottom: 10px;
}
button {
margin-left: 20px;
}
</style>
</head>
<body>
<div id="app">
<div class="inputbox">
<input type="text" v-model="inputText">
</div>
<button>点击搜索</button>
</div>
</body>
</html>
<script src="vue-2.5.21.js"></script>
<script src="05、监听.js"></script>
js文件
// Vue实例中的el,data,methods,computed,watch 都是Vue实例的选项。
// 这些选型的名字是固定的,而且只能写一个
var vm = new Vue({
el: '#app',
data: {
//定义响应式数据
inputText: '',
arr: [],
obj: {
name: '李煜', age: 30 }
},
methods: {
//定义方法
add() {
}
},
computed: {
//定义计算属性
},
watch: {
//设置监听
inputText(newValue, oldValue) {
//每当inputText的值发生改变,inputText这个监听函数就会自动执行,通过参数newValue就可以获取inputText的最新值
// console.log(newValue, this.inputText);
console.log('获取到了输入的最新值,发起网路请求');
},
arr() {
//监听数组 arr 的改变
console.log('监听到arr发生改变了');
},
obj: {
//监听对象 obj 的改变
handler() {
//监听回调
console.log('监听到obj发生改变了');
},
deep: true,//开启深度监听
//immediate: true,//初始化执行监听回调
}
}
})
4.过滤器
vue.js在2.0版本中,相对于1.0版本做了比较大的改动,2.0版本中,过滤器只能用于{ {}}中。1.0版本中指令(如:v-for,v-on等)里边的过滤器在2.0版本中都放在计算属性中。同时1.0版本中的所有内置过滤器(如:capitalize等)全部取消了。下边通过一个实际的例子说明2.0版本中过滤器的用法。代码如下:
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号 | 指示:
示例代码:
APP.vue文件中
<template>
<!-- 一个.vue文件就是一个组件, 一个项目中只有一个根组件 App.vue -->
<!-- 一个.vue文件内部一般是由三部分组成: template , script , style -->
<!-- template 内部写标签 , 只能有一个根元素 -->
<!-- script 内部写js逻辑 , 内部需要 export default {}, 所有的js代码都需要写在这里 -->
<!-- style 内部写css样式 , 可以通过lang='xx'指定style内部的css语法 , 可以通过设置 scoped 属性 让多个.vue文件之间的样式互不影响 -->
<div id="app">
<h1>{
{ title }}</h1>
<h1>{
{ sum }}</h1>
<h1>{
{ sex }}</h1>
<h1>{
{ arr }}</h1>
<h1>{
{ obj.age }}</h1>
<h1>{
{ phone | phoneFilter }}</h1>
<h1>{
{ today | todayFilter }}</h1>
</div>
</template>
<script>
export default {
data() {
//定义响应式数据
return {
title: "今天又是美好的一天",
sum: 666,
sex: false,
arr: [],
obj: { age: 888 },
phone: "19893311146",
today: new Date(),
};
},
cumputer: {
//定义计算属性
},
methods: {
//定义方法
},
watch: {
//设置监听
},
filters: {
//定义过滤器(局部变量)
// 手机号码过滤器
// phoneFilter(phone) {
// return phone.slice(0, 3) + "****" + phone.slice(-4);
// },
// // 时间过滤器
// todayFilter(today) {
// return (
// today.getFullYear() +
// "-" +
// today.getMonth() +
// "-" +
// today.getDate() +
// " " +
// today.getHours() +
// ":" +
// today.getMinutes() +
// ":" +
// today.getSeconds()
// );
// },
},
};
</script>
<style lang="scss" scoped>
</style>
main.js文件中
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 定义全局过滤器(可以在所有的.vue文件中使用)
Vue.filter('phoneFilter', (phone) => {
return phone.slice(0, 3) + "****" + phone.slice(-4);
})
Vue.filter('todayFilter', (today) => {
return (
today.getFullYear() +
"-" +
today.getMonth() +
"-" +
today.getDate() +
" " +
today.getHours() +
":" +
today.getMinutes() +
":" +
today.getSeconds()
);
})
//实例化Vue对象
new Vue({
render: h => h(App),
}).$mount('#app')