专业的编程技术博客社区

网站首页 > 博客文章 正文

web前端框架Vue基础二(vue前端架构设计)

baijin 2024-09-14 00:09:46 博客文章 6 ℃ 0 评论

学习大纲

表单输入绑定

思考:之前写项目如何获取表单中的数据

回答:步骤1给搜索框增加id属性,步骤2通过选择器获取里面的内容

现在:要告诉大家一个更简单的方法

专业术语:数据双向绑定

简介&语法

  • 单向绑定:M 自动同步 V
  • 双向绑定:M 自动同步 V && V 自动同步 M
  • 语法:v-model="data中的键" (仅支持input/textarea/select)

练习

  • 单向绑定:模型放msg和url属性 同步到视图
  • 双向绑定:input框修改查看模型数据变化
  • 其他:textarea、checkbox、radio练习
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vue</title>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
    <h1>单向绑定</h1>
    <div>{{msg}}</div>
    <div>{{url}}</div>
    <a :href="url">点我</a>

    <h1>双向绑定(仅支持input/textarea/select)</h1>
    <input type="text" v-model="msg" />

    <h1>其他:textarea、checkbox、radio练习</h1>
    <textarea cols="30" rows="10" v-model="textareaContent"></textarea>
    <b>{{textareaContent}}</b>

    <hr />
    兴趣爱好(兴趣爱好多个值 用数组):
    <input type="checkbox" value="玩小黄鸭" v-model="checkboxContent"/> 玩球
    <input type="checkbox" value="篮球" v-model="checkboxContent" /> 篮球
    <input type="checkbox" value="足球" v-model="checkboxContent" /> 足球
    <input type="checkbox" value="挤痘痘" v-model="checkboxContent" /> 挤痘痘
    <input type="checkbox" value="臭脚" v-model="checkboxContent" /> 臭脚
    <br />
    {{checkboxContent}}

    <hr />
    性别:
    <input type="radio" name="sex" value="男" v-model="radioContent" > 男
    <input type="radio" name="sex" value="女" v-model="radioContent"> 女
    <input type="radio" name="sex" value="特殊群体" v-model="radioContent"> 特殊群体
    <br />
    {{radioContent}}
    <br />
    <br />
    <br />
    <br />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// - 单向绑定:模型放msg和url属性 同步到视图
// - 双向绑定:input框修改查看模型数据变化
// - 其他:textarea、checkbox、radio练习

let vm = new Vue({
    el: '#app',
    data: {
        msg: "测试数据",
        url: "http://qf.com",

        textareaContent: "测试数据",
        checkboxContent: [], //切记切记切记 checkbox多个值 必须是数组
        radioContent: "特殊群体"
    }
})
</script>
</body>
</html>

小总结

双向绑定:可以讲模型数据同步到视图,并且视图数据可以同步到模型的表现

语法:v-model=“data中的键” (仅针对input/textarea/select)

脚下留心:针对input:checkbox 模型中必须是数组,其他都是字符串

实战:购物车案例&修饰符

  • 需求
步骤1:赋值下述代码&遍历显示模型数据 (数据在模型的carts中)
步骤2:勾选商品显示数据 (勾选的数据放到chooseCarts:[]中)
步骤3:添加数据+1	    (触发addCartFn方法,模型carts数据+1)
步骤4:统计			 (封装totalFn方法)
步骤5:全选&全不选      (封装chooseCartsFn方法)
步骤6:细节优化(input框单击同步、input框输入同步,input框只能输入数字)
  • 需求代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>购物车</h1>
      <input type="checkbox" /> 全选&全不选
      <hr />
      <ul>
        <li >
          <input type="checkbox" value=""  />  
          标题:,
          价格:, 
          数量: 
          <input type="text" size="1"  />
          <input type="button" value="+"  />
        </li>
      </ul>
      <hr /><hr />
      <h2>勾选商品</h2>
      <h2>总数量:,总价:</h2>
    </div>
    <script>
      new Vue({
        el: '#app',
        data: {
          //购物车商品
          carts: [
            {title:'商品1', price: 1, number: 1},
            {title:'商品2', price: 2, number: 1},
            {title:'商品3', price: 3, number: 1}
          ]
        },
        //声明普通方法
        methods: {
        }
      })
    </script>
  </body>
</html>
  • 完成代码
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>购物车</h1>
<input type="checkbox" @click="chooseCartsFn"/> 全选&全不选
<hr />
<ul>
    <li v-for="(cart,index) in carts">
        <!-- 加下留心:逻辑上加点击事件,但是这边被vue封装了 所以改成change事件 -->
        <input type="checkbox" :value="cart" v-model="chooseCarts" @change="totalFn" />  
        标题:{{cart.title}},
        价格:{{cart.price}},
        数量:{{cart.number}} 
        <!-- <input type="text" :value="cart.number" size="1"  /> -->
        <input type="text" v-model.number="cart.number" size="1" @keyup="totalFn" />
        <input type="button" value="+" @click="addCartFn(index)"/>
    </li>
</ul>
<hr /><hr />
<h2>勾选商品</h2>
{{chooseCarts}}
<h2>总数量:{{totalNum}},总价:{{totalPrice}}</h2>
</div>
<script>
// 步骤1:赋值下述代码&遍历显示模型数据 (数据在模型的carts中)
// 步骤2:勾选商品显示数据 (勾选的数据放到chooseCarts:[]中)
// 步骤3:添加数据+1	    (触发addCartFn方法,模型carts数据+1)
// 步骤4:统计			 (封装totalFn方法)
// 步骤5:全放&全不选       (封装chooseCartsFn方法)
// 步骤6:细节优化(input框单击同步、input框输入同步,input框只能输入数字)

new Vue({
    el: '#app',
    data: {
        // 存放勾选商品
        chooseCarts: [],
        //购物车商品
        carts: [
            {title:'商品1', price: 1, number: 1},
            {title:'商品2', price: 2, number: 1},
            {title:'商品3', price: 3, number: 1}
        ],
        // 总的购买数量和购买价格
        totalPrice: 0,
        totalNum: 0
    },
    //声明普通方法
    methods: {
        chooseCartsFn() {
            // 假设 chooseCarts 长度 没有3个  也就是没有全部都打钩
            // 就 全部够
            // 否则 全部不够
            if (this.chooseCarts.length == 3)
            {
                this.chooseCarts = []
            } else {
                this.chooseCarts = this.carts
            }

            // 调用模型:this.data中的键
            // 调用方法:this.方法名()
            // this就是vm这个对象

            this.totalFn()
        },
        addCartFn(index) {// index指当前操作的购物车商品
            // this.carts 获取模型数据
            this.carts[index].number += 1
        },
        totalFn() {
            // 声明临时变量存放数据
            let tmpTotalNum = 0
            let tmpTotalPrice = 0
            // 遍历选择的商品 进行统计
            for (let i = 0; i < this.chooseCarts.length; i++)
            {
                tmpTotalNum += this.chooseCarts[i].number
                tmpTotalPrice += this.chooseCarts[i].number * 
                                 this.chooseCarts[i].price 
            }
            // 修改模型数据
            this.totalNum = tmpTotalNum
            this.totalPrice = tmpTotalPrice
        }
    }
})
</script>
</body>
</html>

Class与Style绑定

class="left header"

class="data中的键 有时候还有放多个data中的键"

注:怎么放?可不是简单的加空格

思考:标签的class和style属性 一定是固定的 没有情况需要放模型数据吗?

回答:肯定有

解决:通过手册Class与Style绑定 就是给class和style属性值 改成data中的键

语法

class使用模型数据
单个【直接写字符串】
多个-数组【数组中的每个值就是要显示的class】
多个-对象【键就是要显示的class,值来控制是否展示bool】

style使用模型数据
多个-对象【键是css属性名,值是css属性值】
多个-数组【上面一个个对象】

练习

  • 需求:给class和Style绑定模型数据
  • 需求代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    .bgRed {background: red;}
    .bgBlue {background: blue;}
    .bgGreen {background: green;}
    .fontRed {color: red;}
    .fontBlue {color: blue;}
    .fontGreen {color: green;}
    </style>
  </head>
  <body>
    <div id="app">
        <!-- bgRed -->
        <h1>class绑定模型数据(字符串语法)</h1>
        
        <!-- bgBlue显示该类/fontRed不现实该类 -->
        <h1>class绑定模型数据(对象语法) </h1>  
        <h1>class绑定模型数据(数组语法)</h1>
        <!-- bgGreen/fontRed -->

        <!-- 背景红色/字体20px -->
        <h1>style绑定模型数据(对象语法)</h1>
        <h1>style绑定模型数据(数组语法)</h1>
        <!-- 背景黄色 -->
    </div>
  </body>
</html>
  • 完成代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    .bgRed {background: red;}
    .bgBlue {background: blue;}
    .bgGreen {background: green;}
    .fontRed {color: red;}
    .fontBlue {color: blue;}
    .fontGreen {color: green;}
    </style>
  </head>
  <body>
    <div id="app">
        <!-- 
            bgRed 
            传统
            <h1 class="bgRed">class绑定模型数据(字符串语法)</h1>

            但是:现在我想讲bgRed这个类 变成模型中的键
            通过:动态参数 v-bind  但是我们简写 :
        -->
        <h1 v-bind:class="classString">class绑定模型数据(字符串语法)</h1>
        
        <!-- bgBlue显示该类/fontRed不现实该类 -->
        <h1 v-bind:class="classObj">class绑定模型数据(对象语法) </h1>  
        <h1 v-bind:class="classArr">class绑定模型数据(数组语法)</h1>
        <!-- bgGreen/fontRed -->

        <!-- 背景红色/字体20px -->
        <h1 v-bind:style="styleObj">style绑定模型数据(对象语法)</h1>
        <h1 v-bind:style="styleArr">style绑定模型数据(数组语法)</h1>
        <!-- 背景黄色 -->
    </div>
    <script>
    new Vue({
        el: "#app",
        data: {
            classString: "bgRed", 
            classObj: {"bgBlue":true, "fontRed": true},
            classArr: ["bgGreen", "fontRed"],
            styleObj: {"background": "red", "font-size": "20px"},
            styleArr: [
                {"background": "yellow"},
                {"color": "green"}
            ] 
        }
    })
    </script>
  </body>
</html>

小总结

class

一个类      【模型中直接写字符串】
多个类-对象  【对象的键-就是类名,对象的值-布尔型控制类名是否显示】
多个类-数组  【数组中的值就是要显示的类名】

style

对象   【对象的键-就是CSS属性名,对象的值-就是CSS属性值】
数组   【数组中值-是一个个对象,每个对象由  CSS属性名:CSS属性值

四、ToDoList案例

完成下述案例

步骤1:循环显示模型数据
步骤2:添加数据放到模型中
步骤3:点击删除 移除模型数据
静态效果地址:https://github.com/webopenfather/ToDoList


步骤1:循环显示模型数据

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>todolist</title>
	<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
</head>
<style type="text/css">
	ul li { list-style: none; }
	.main { width: 100%; display: flex; align-items: center; justify-content: center; margin: 15px 0px;}
	.cc { float: right; }
	td { display: flex; align-items: center; justify-content: space-between; padding: 5px 20px !important; }
</style>
<body>
	<div class="container" id="app">
		<h1 style="text-align: center;">ToDoList</h1>
		<div class="main">
			<div class="left">
				 <input type="text" class="form-control" id="exampleInputEmail1" placeholder="请输入内容" />
			</div>
             <div class="right">
             	 <!-- 添加 -->
				<button type="button" class="btn btn-primary">添加</button>
             </div>
		</div>
		<table class="table table-condensed">
			<tr>
		      <td class="active" v-for="todo in todos">
			      {{todo.title}}
			      <button type="submit" class="btn btn-default cc">
			      删除
			      </button>
			  </td>
			</tr>
		</table>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script>
	new Vue({
		el: "#app",
		data: {
			todos: [
				{title: "吃饭"},
				{title: "睡觉"},
				{title: "欺负钱某"}
			]
		}
	})
	</script>
</body>
</html>


步骤2:添加数据放到模型中


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>todolist</title>
	<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
</head>
<style type="text/css">
	ul li { list-style: none; }
	.main { width: 100%; display: flex; align-items: center; justify-content: center; margin: 15px 0px;}
	.cc { float: right; }
	td { display: flex; align-items: center; justify-content: space-between; padding: 5px 20px !important; }
</style>
<body>
	<div class="container" id="app">
		<h1 style="text-align: center;">ToDoList</h1>
		<div class="main">
			<div class="left">
				 <input type="text" class="form-control" id="exampleInputEmail1" placeholder="请输入内容" v-model="content" />
			</div>
             <div class="right">
             	 <!-- 添加 -->
				<button type="button" class="btn btn-primary" @click="add">添加</button>
             </div>
		</div>
		<table class="table table-condensed">
			<tr>
		      <td class="active" v-for="todo in todos">
			      {{todo.title}}
			      <button type="submit" class="btn btn-default cc">
			      删除
			      </button>
			  </td>
			</tr>
		</table>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script>
	new Vue({
		el: "#app",
		data: {
			todos: [
				{title: "吃饭"},
				{title: "睡觉"},
				{title: "欺负钱某"}
			],

			// todo内容
			content: ""
		},
		// 声明普通方法
		methods: {
			add() {
				// 这里面应该给模型todos增加数据
				// this.todos.push({
				// 	title: "所x"
				// })

				// 发现:上述代码写死了
				// 传统:1-加id或class,2-获取
				// 现在:1-双向绑定同步到模型中,2-哪里需要直接操作模型
				this.todos.push({
					title: this.content
				})
				// 清空模型
				this.content = ""
			}
		}
	})
	</script>
</body>
</html>

步骤3:点击删除移除模型数据

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>todolist</title>
	<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
</head>
<style type="text/css">
	ul li { list-style: none; }
	.main { width: 100%; display: flex; align-items: center; justify-content: center; margin: 15px 0px;}
	.cc { float: right; }
	td { display: flex; align-items: center; justify-content: space-between; padding: 5px 20px !important; }
</style>
<body>
	<div class="container" id="app">
		<h1 style="text-align: center;">ToDoList</h1>
		<div class="main">
			<div class="left">
				 <input type="text" class="form-control" id="exampleInputEmail1" placeholder="请输入内容" v-model="content" />
			</div>
             <div class="right">
             	 <!-- 添加 -->
				<button type="button" class="btn btn-primary" @click="add">添加</button>
             </div>
		</div>
		<table class="table table-condensed">
			<tr>
		      <td class="active" v-for="(todo, index) in todos">
			      {{todo.title}}
			      <button type="submit" class="btn btn-default cc" @click="del(index)">
			      删除
			      </button>
			  </td>
			</tr>
		</table>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script>
	new Vue({
		el: "#app",
		data: {
			todos: [
				{title: "吃饭"},
				{title: "睡觉"},
				{title: "欺负钱某"}
			],

			// todo内容
			content: ""
		},
		// 声明普通方法
		methods: {
			del(index) {
				// alert(111)
				// 实战:传递ID  异步请求  删除
				// 现在:数据是固定在模型中的   不用请求接口  直接从模型中移除一条数据
				// 
				// 作用:从数组中删除一个元素
				// 语法:数组.splice(从第几个开始删 下标, 删的个数)

				this.todos.splice(index,1)
			},
			add() {
				// 这里面应该给模型todos增加数据
				// this.todos.push({
				// 	title: "所x"
				// })

				// 发现:上述代码写死了
				// 传统:1-加id或class,2-获取
				// 现在:1-双向绑定同步到模型中,2-哪里需要直接操作模型
				this.todos.push({
					title: this.content
				})
				// 清空模型
				this.content = ""
			}
		}
	})
	</script>
</body>
</html>


#五、axios 与 fetch 实现数据请求

明确需求

思考:在vue中如何发送异步请求获取数据

回答:传统(ajax、jq $.ajax) 现在(axios、fetch)

axios简介&语法

Axios[?k'si:??]是一个用JS写的HTTP库(配合vue使用从而获取接口数据)

基于ajax和promise封装的

-----------------------------------

  • 手 册:https://www.kancloud.cn/yunye/axios/234845
  • 库地址:https://cdn.bootcss.com/axios/0.18.0/axios.js
  • GET请求/POST请求
axios({
url
method
data
headers
}).then().catch()


###GET
axios({
    method:"get"
    //方案1
    //url:"http://118.31.9.103/请求路径?参数1=值1&....&参数n=值n",
    //方案2(推荐)
    url:"http://118.31.9.103/请求路径",
    params: {键:值,...,键n:值n}
}).then(res => {
}).catch(error=>{
  console.log(error)
})


###POST
axios({
    url:"http://118.31.9.103/请求路径",
    method:"post",
    data:"参数1=值1&....&参数n=值n"
}).then(res => {
}).catch(error=>{
  console.log(error)
})


多学一招
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])

axios练习

  • 需求1:在day2目录下创建data.json接口文件
{
    "meta": {
    	"msg": "提示信息",
    	"status": 200
    },
    "data": [
        {"id": 1, "title": "test1"},
        {"id": 2, "title": "test2"},
        {"id": 3, "title": "test3"},
        {"id": 4, "title": "test4"}
    ]
}
  • 需求2:通过axios请求data.json本地文件
  • 需求3:通过axios请求线上“卖座电影正在热映”
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Vue</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <h1>本地请求</h1>
            <button @click="fn1">点击请求</button>
            <h1>线上请求</h1>
            <button @click="fn2">点击请求</button>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    fn1Data: [],
                    fn2Data: []
                },
                methods: {
                    fn1() {
                        axios({
                            url: "./data.json",
                            method: "get"
                        }).then(res => {
                            // console.log(res)
                            // 将响应的数据保存到 模型中
                            this.fn1Data = res.data.data
                            console.log(res.data.data)
                        }).catch(err => {
                            console.log(err)
                        })
                    },
                    fn2() {
                        axios({
                            url: "https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=4101518",
                            method: "get",
                            headers: {
                                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"15747611471361504633687","bc":"110100"}',
                                'X-Host': 'mall.film-ticket.film.list'
                            }
                        }).then(res => {
                            // console.log(res)
                            // 将响应的数据保存到 模型中
                            this.fn2Data = res.data.data.films
                            console.log(res.data.data.films)
                        }).catch(err => {
                            console.log('this is err')
                            console.log(err)
                        })
                    }
                }
            })
        </script>
    </body>
</html>

fetch简介&语法

fetch(请求地址,{
 method: 请求方式,
 headers:{},
//body:"name=kerwin&age=100"
 body:JSON.stringify({
    数据1: 值1,
    数据n: 值n
 })
}).then(res=> res.json()).then(res=>{
 console.log(res);
})

fetch练习

  • 需求1:通过axios请求data.json本地文件
  • 需求2:通过axios请求线上“卖座电影正在热映”
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Vue</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
                <h1>本地请求</h1>
                <button @click="fn1">点击请求</button>
                <h1>线上请求</h1>
                <button @click="fn2">点击请求</button>

                <div v-for="film in films">
                    <p>编号:{{ film.filmId}}</p>
                    <p>标题:{{ film.name}}</p>
                    <img v-bind:src="film.poster" width="300" height="150" />
                    <!-- <img :src="film.poster" width="300" height="50" /> -->
                </div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    // 正在热映
                    films: []
                },
                // 声明普通方法
                methods: {
                    fn2() {
                        fetch('https://m.maizuo.com/gateway?cityId=410500&pageNum=1&pageSize=10&type=1&k=2817913', {
                            method: 'get',
                            headers: {
                                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"15748374011636382539989","bc":"410500"}',
                                'X-Host': 'mall.film-ticket.film.list'
                            }
                        })
                        .then(res => res.json())
                        .then(res => {
                            console.log(res)
                            this.films = res.data.films
                        })
                    },
                    // fn1: function(){}
                    // fn1: () => {}
                    fn1() {
                        fetch('./data.json',{
                            method: 'get',
                            // headers:{},
                            //body:"name=kerwin&age=100"
                            // body:JSON.stringify({
                            //     数据1: 值1,
                            //     数据n: 值n
                            // })
                            })
                            // .then(res=> {
                            //     // console.log(res)
                            //     // console.log(res.json())  // 返回的promise对象

                            //     return res.json()
                            // })
                            .then(res=> res.json())
                            .then(res=>{
                                console.log(res);
                            })
                    }
                }
            })
        </script>
    </body>
</html>

小总结(异步请求区别和选择ajax/jq/axios/fetch)

ajax/jq/fetch关系

最初ajax  瑕疵:1-异步回调地狱,2-语法麻烦,3-语法有兼容性问题
后来jq    明确:基于ajax封装
		 好处:语法更简单、解决兼容性问题
		 瑕疵:异步回调地狱
	
官方是如何解决异步回调地狱的:promise

最后:fetch  官方封装的 不需要导入库直接使用(fetch = XMLHttpRequest + promise)

fetch和axios(面试)

明确:vue 以前  vue-resource(官方的 后来官方推荐别用  推荐你用axios 第三方的)

相同点:
1.都是项目用来发送异步请求的
2.都是基于XMLHttpRequest + promise
不同点:
1- axios是第三方封装的,fetch是官方封装的
2- axios更强(并发&拦截器 -> 写项目说)
3- fetch每次都需要then res.json()

六、计算属性和侦听器

1、计算属性(明确需求)

  • 说明:视图主要负责展示数据,但是在视图写过多的逻辑
  • 思考:是否有利于后期维护
  • 回答:不行
  • 解决:以前(封装起来,直接调用) 现在(计算属性)
  • 特色:1-减少代码冗余便于维护,2-有缓存

2、计算属性(语法)

定义

new Vue({
    el,
    data,
    methods,
    // 声明计算属性(名词就是普通方法升级版:1-减少代码冗余,2-提高性能 通过缓存)
    computed: {
        方法1,
        ...
        方法n
    }
})

调用:{{ 计算属性函数名 }} 切记切记普通函数升级版 所以不需要叫小括号调用

3、计算属性(练习)

  • 效果图
  • 代码:
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Vue</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <h1>翻转字符串</h1>
            <p>默认显示: {{ msg }}</p>
            <p>简单实现: {{ msg.split('').reverse().join('') }} (后期如果多个地方调用,不便于维护)</p>
            <p>简单实现2: {{ msg.split('').reverse().join('') }} (后期如果多个地方调用,不便于维护)</p>
            <p>普通方法: {{ reverseStrFn() }}</p>
            <p>普通方法2: {{ reverseStrFn() }} (注:如果封装的代码特别耗性能)</p>
            <p>计算属性: {{ reverseStrComputed }} </p>
            <p>计算属性2: {{ reverseStrComputed }} </p>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    msg: "hello,webopenfather"
                },
                // 声明普通方法
                methods: {
                    reverseStrFn() {
                        console.log(111)
                        return this.msg.split('').reverse().join('')
                    }
                },
                // 声明计算属性
                computed: {
                    reverseStrComputed() {
                        console.log(222)
                        // 发现:计算属性定义语法和普通方法一毛一样
                        // 但是:特性不一样(多个一个缓存)
                        // 小心:调用不一样 不需要小括号
                        return this.msg.split('').reverse().join('')
                    }
                }
            })
        </script>
    </body>
</html>


4、侦听器(明确需求)

思考:大家后期做商城项目,是否需要写搜索功能

回答:肯定

思考:以前如何写搜索的

回答:1-给搜索框增加键盘松开事件,2-获取内容,键盘松开之后发送异步请求

现在:新技术侦听器

5、侦听器(语法)

侦听器:名词解释不清,也是方法的升级版 可以监听模型数据变化,交给函数处理

定义

new Vue({
    el
    data
    methods
    computed
    watch: {
        ....
        // 留心:函数名就是你需要监控的模型数据(也就是说函数名模型中data键)
        函数名(新数据, 旧数据) {// 脚下留心:形参是系统传递进来的
            
        }
    }
})


调用:不能调用,实战一般怎么用 (将数据保存到模型新数据中,然后视图遍历)

6、侦听器(练习)

  • 需求:在页面显示搜索框,用户输入内容 同步页面输出
  • 上述需求目的:验证侦听器可以监控数据变化,并交给函数处理
  • 代码:
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Vue watch</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            搜索框:
            <input type="text" v-model="search">

            <hr />
            {{search}}
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    search: "",

                    searchData: []
                },
                // 声明侦听器
                watch: {
                    // 脚下留心:函数名不是乱写的
                    // 而是:要监听的模型数据
                    search(newData, oldData) {
                        console.log('新数据:', newData, '旧数据:',oldData)
                        // 发送异步请求
                        // axios 得到数据 res

                        // 思考:数据如何在页面展示呢?
                        // 回答:保存到模型中即可  this.searchData = res.data
                    }
                }
            })
        </script>
    </body>
</html>


7、计算属性和侦听器区别

  • 相同点:研发目的(避免在视图写太多逻辑,导致后期难维护)
  • 不同点:
1计算属性(直接通过函数名调用)  侦听器(不能调用 借助模型调用)
2计算属性(有缓存)			  侦听器(没有)

3计算属性(一个【键/函数名】监控【n个数据变化 用了几个就监控几个】) 
  侦听器 (一个【键/函数名】监控【一个数据变化】)
  • 代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>计算属性和监听器的区别</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <p>
                姓:
                <input type="text" v-model="xing">
            </p>
            <p>
                名:
                <input type="text" v-model="ming">
            </p>

            <hr />
            姓名(直接搞):{{xing}}{{ming}} 或 {{xing+ming}} <br />
            姓名(普通方法):{{ fullNameFn() }}              <br />
            姓名(计算属性):{{ fullNameComputed }}          <br />
            姓名(侦听器):{{ fullName }}          <br />
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    xing: "",
                    ming: "",

                    fullName: ""
                },
                methods: {
                    fullNameFn() {
                        return this.xing + this.ming // 模型变了 受到影响 监控多个数据
                    }
                },
                // 声明计算属性
                computed: {
                    fullNameComputed() {
                        return this.xing + this.ming  // 模型变了 受到影响 监控多个数据
                    }
                },
                // 声明侦听器
                watch: {
                    xing(newData, oldData) {
                        // 注:结果要借助模型展示
                        // this.fullName = this.xing + this.ming
                        this.fullName = newData + this.ming
                    },
                    // ming(newData, oldData) {
                    //     this.fullName = this.xing + newData
                    // }
                }
            })
        </script>
    </body>
</html>


8、小总结

  • 什么时候用普通方法:1-事件调用,2-视图有太多相同代码 封装使用普通方法
  • 什么时候用计算属性:普通方法多次调用并且每次单个调用耗性能 -> 通过计算属性优化
  • 什么时候用侦听器:数据变化后不是直接显示,还需要逻辑
  • 语法潜规则
new Vue({
    el
    data
    methods
    // 声明计算属性
    computed: {
        方法   // 1-普通方法升级版,2-调用不加小括号,3-有缓存,
        	  // 4-如果里面有操作模型了 就会再次触发重新缓存
    },
    // 声明侦听器
    watch: {
        // 函数名就是data中的键  必须是
        方法   // 1.普通方法升级版,2-不能调用需要借助模型
        	  // 3.每次只能监控一个数据
    }
})

思考:为什么搜索用侦听器而不是计算属性
回答:计算属性的唯一特性就是缓存,但是搜索后每次都要重新调用 破坏了缓存, 没必要用了。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表