2.4 计算属性
从字符串反转中,我们发现
-
插值语法的初衷是用于简单运算。明显练习题中的写法,违背了插值语法的初衷。
-
methods方法可以。但是方法中如果封装的是性能开销比较大的逻辑代码,需要进行大量的运算,并且别的属性还依赖这个方法,那不可避免的是,这个方法可能还要执行很多次。 这种情况,对CPU的性能开销可想而知,有多巨大了。
而Vue引入了计算属性来解决这个问题,它提供了缓存机制。如果重复调用计算属性,就使用缓存数据,提高性能。
完整语法格式:
computed:{ 属性名:{get(){ //提供get方法,1. 初始加载时调用 2.所依赖的值被改变时}set(value){ //提供set方法,1. 当对应的计算属性fullName的值主动修改时}} }
简化语法格式: 只有确定 属性为只读时,才能使用简化写法。
computed:{ 属性名(){//....其实是get方法逻辑} }
<!-- 计算属性:-1. 定义: 要用的属性不存在,要通过已有属性计算得来-2. 原理: 底层借助了Object.difineProperty方法提供的getter和setter-3. get函数什么时候执行(1) 初次读取时会执行一次(2) 当依赖的数据发生变化时会再次被调用-4. 优势: 与methods实现相比,内部有缓存机制(重复使用),效率更高,调试方便-5. 备注:(1) 计算属性最终会出现在vm上,直接读取即可。(2) 如果计算属性要被修改,那必须使用set函数,且set函数中要对计算时所依赖的属性进行修改 -6. 与方法的比较(1). 计算属性,在调用时不加(),原因:调用的是属性, 重复调用,走缓存(2). methods方式,在调用时,必须添加(), 原因:调用的是函数,没有缓存机制 -->
2.5 侦听属性
2.5.1 介绍
侦听(监听) 就是对 内置对象的状态或者属性进行监听,如果发生了变化,就做出一些相应的处理操作。
在 Vue.js 中,监视属性是用于观察 Vue 实例中的数据变动的一种机制,当需要在数据变化时执行异步或开销较大的操作时,适合使用监听属性watch
。
-
语法1:在Vue中添加watch属性
// 完整写法 watch: {`被监听的属性名`:{immediate: true, //Vue初始化时,就调用一次回调函数handlerdeep:true, //开启深度监听handler(newValue,oldValue){ //回调函数//第一个参数,是被监听属性的新值//第二个参数,是被监听属性的旧值}} } //简化写法 watch: {被监听属性名(newValue,oldValue){//第一个参数,是被监听属性的新值//第二个参数,是被监听属性的旧值}} }
-
语法2: 使用vm实例绑定watch方法
vm.$watch("被监听属性名", {immediate: true, deep: true,handler(newValue, oldValue) {//....} }) //简化写法 vm.$watch("被监听属性名",function(newValue,oldValue){//... })
-
当被监视的属性变化时,回调函数自动调用
-
监视的属性必须存在,才能被监视
2.5.2 案例演示
<div id="demo"><input type="text" v-model="weather" placeholder="请输入天气"> <br><input type="text" v-model="hobbies.hobby1" placeholder="请输入爱好1"> <br><input type="text" v-model="hobbies.hobby2" placeholder="请输入爱好2"> <br> </div>
2.5.3 计算属性与监视属性的区别
计算属性是依赖的值改变后重新计算结果更新DOM,会进行缓存。
属性监听的是属性值,当定义的值发生变化时,执行相对应的函数。
最主要的用途区别: 计算属性不能执行异步任务。计算属性一般不会用来向服务器请求或者执行异步任务,因为耗时可能会比较长,我们的计算属性要实时更新。所以这个异步任务就可以用监听属性来做。
总而言之:computed能实现的,watch都能实现,computed不能实现的,watch也能实现
2.6 列表练习题(计算属性和监听属性)
{id:1001,name:'马冬梅',age:30,gender:'男'}, {id:1002,name:'周冬雨',age:28,gender:'男'}, {id:1003,name:'周杰伦',age:32,gender:'女'}, {id:1004,name:'温兆伦',age:22,gender:'女'}
1)列表过滤
2)列表排序
2.7生命周期
2.8 练习题
2.7.1 样式属性练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 第一步: 引入vue文件 -->
<script type="text/javascript" src="../js/vue.js"></script><style>
.basic{
border: 1px red solid;
width: 400px;
height: 100px;
}/* 下面的三个样式,使用其中一个 */
.r1{
border: 10px blue dotted;
background-color: gray;
}
.r2{
border: 10px orange dashed;
background-color: green;
}
.r3{
border: 10px red double;
background-color:burlywood;
}
/* 下面的三种样式,可能会使用其中1个,或者2个,或者三个,或者一个都不用 */
.c1{
font-size: 30px;
font-style: italic;
}
.c2{
border-radius: 20px;
}
.c3{
background: linear-gradient(to right, green,rgb(0, 225, 255));
}
</style>
</head>
<body>
<!-- 绑定样式:
1. class样式
:class="xxx" xxx可以是字符串,对象,数组
-字符串写法适用于:类名不确定,要动态获取
-对象写法适用于:要绑定多个样式,个数确定,名字确定,但是不确定用不用
-数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
2. style样式
:style="{fontSize:xxx}" 其中xxx是动态值
:style="[a,b]" 其中a、b是样式对象
-->
<!-- 第二步: 准备容器 -->
<div id="demo">
<!-- 绑定class样式--字符串写法 ,适用于样式的类名不确定,需要动态指定 --> -->
<div class="basic" :class="classStyle">
欢迎来到{{name}}学习 <br><br>
<button @click="change1">点我改变样式</button>
</div> <br><br><!-- 绑定class样式:对象写法,适用于要绑定的样式个数确定,名字确定,但要动态决定用不用 -->
<div class="basic" :class="classObject">
欢迎来到{{name}}学习 <br><br>
</div> <br><br><!-- 绑定class样式:数组写法,适用于要绑定的样式个数不确定,名字也不确定 -->
<div class="basic" :class="classArr">
欢迎来到{{name}}学习 <br><br>
</div> <br><br>
<!-- 绑定style样式: 对象写法 -->
<div class="basic" :style="styleObject">
欢迎来到{{name}}学习 <br><br>
</div> <br><br><!-- 绑定style样式: 数组写法 -->
<div class="basic" :style="styleArr">
欢迎来到{{name}}学习 <br><br>
</div> <br><br>
</div>
</body>
<script>
// 第三步: 创建Vue实例
new Vue({
// 第四步: 设置挂载点, 以及配置数据
el:"#demo",
data:{
name:"水利电力学院",
classStyle:"",
// index:0,
classObject:{
c1:false,
c2:true,
c3:true
},
classArr:['c1','c2','c3'],
styleObject:{
fontSize:'40px',
backgroundColor:"red"
},
styleArr:[
{fontSize:'40px'},
{backgroundColor:"blue"}
]
},
methods: {
change1(){
var arr = ["r1","r2","r3"]
var index = Math.floor(Math.random()*3)
this.classStyle = arr[index]
}
},
})
</script>
</html>
2.9 自定义指令
<!-- 自定义指令定义语法:
1. 局部指令:
写法1:
new Vue({
directives:{指令名:配置对象}
})
写法2:
new Vue({
directives:{指令名:回调函数}
})
2.全局指令:
Vue.directive(指令名,配置对象)
Vue.directive(指令名,回调函数)3. 配置对象中常用的3个回调函数:
bind(element,binding):指令与元素成功绑定时调用
inserted(element,binding):指令所在元素被插入页面时调用
update(element,binding):指令所在模板结构被重新解析时调用
4. 备注:
指令定义时不加“v-”,但使用时要加“v-”
指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名new Vue({
//...
directives:{
'my-text'(element,binding){
element.innerText = binding.value * 10
}
}
//...
})
-->
三 组件化开发
3.1 传统方式和组件方式编写应用比较
组件:就是实现应用中局部功能代码和资源的整合
组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。 以上图为例。
组件化的好处:便于维护,利于复用,从而提升开发效率。
组件分类:普通组件、根组件。
比如:下面这个页面,可以把所有的代码都写在一个页面中,但是这样显得代码比较混乱,难易维护。咱们可以按模块进行组件划分
3.2 非单文件组件的开发
非单文件组件开发,指的是在一个html文件中,包含n个组件。
3.2.1 组件开发的步骤
第一步:定义组件(创建组件)
//定义组件。 与new Vue({...}) 语法类似,但是不能配置el选项。 所有组件都由一个具体的VM实例来管理
const 组件变量 = Vue.extend({
name:'组件名称', //VueDevtools调试面板中显示的组件名
template: `组件模版内容`,
data() { // 必须写成data函数且有返回值,返回js对象格式 ....原因是避免组件被复用时,数据存在引用关系。
return {//....}
},
methods: {
},
//......
})
//简写方式
const 组件变量 = {...} //省略Vue.extend,底层默认调用它。
第二步:注册组件
1. 局部注册:new Vue的时候配置components选项//创建Vuenew Vue({//...components: {//配置各个组件//组件名: 组件变量}}) 2. 全局注册:Vue.component('组件名',组件) //在定时Vue实例来之前注册
组件名的定义:
1. 一个单词时:- 首字母大小写,都可以. 但是开发者工具中显示的都是大写的。 比如 School 2. 多个单词组成时:- 可以使用kebab-case命名法: my-shool - 可以使用CamelCase命名法:MySchool(脚手架里支持这种写法)- 注意: 无论哪种写法,开发者工具中显示的都是大写的。 比如 MySchool 3. 组件里的name选项,是用来配置开发者工具中显示的名字的 4. 组件名不要使用html,css,js中的关键字
第三步:编写组件标签:
在html文件的相应位置,引入组件名 1. 双标记写法:<组件名></组件名> 2. 单标记写法:<组件名/> 该写法会导致后续组件不能被渲染, 在脚手架里使用,是没有问题的
3.2.2 简单案例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>非单文件组件的基本应用</title>
<script type="text/javascript" src="./myjs/vue.js"></script>
</head>
<body>
<div id="app">
<h1>学校信息</h1>
<xuexiao></xuexiao>
<h1>学生信息</h1>
<xuesheng></xuesheng>
</div>
</body>
<script>
const school = Vue.extend({
template: `<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{schoolAddress}}</h2>
<button @click="showInfo">点我弹出学校名称 </button>
</div>`,
data() {
return {
schoolName: "吉林大学",
schoolAddress: "南关区自由大路"
}
},
methods: {
showInfo: function () {
alert(this.schoolName)
}
},})
const student = Vue.extend({
template: `<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{studentAge}}</h2>
</div>`,
data() {
return {
studentName: "michael",
studentAge: 21
}
}
})
//全局注册: 需要在vue实例创建之前定义
Vue.component("xuexiao", school)
Vue.component('xuesheng', student)
//注册组件
new Vue({
el: "#app",
// components: { //局部注册
// xuexiao: school,
// xuesheng: student
// }
})
</script>
</html>
3.2.3 组件的嵌套
1)书写规则
1. 子组件要先创建。父组件后创建。 原因:父组件里要使用子组件的名,js而且是从上向下解析的
2. 在父组件的定义期间,来注册子组件。
3. 在父组件的定义期间,在template中调用子组件
代码如下:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>非单文件组件的基本应用</title><script type="text/javascript" src="./myjs/vue.js"></script> </head> <body><div id="app"><app></app></div> </body> <script>const school = {template: `<ul><li><span>学校名称:{{schoolName}}</span> <br><span>学校地址:{{schoolAddress}}</span></li></ul>`,data() {return {schoolName: "吉林大学",schoolAddress: "南关区自由大路"}},}const city = {template: `<ul><li>{{city}}<school></school></li> </ul>`,data() {return {city: "长春市",}},components: {school}}const province = {template: `<ul><li>{{province}}<city></city></li></ul>`,data() {return {province: "吉林省"}},components: {city}}const app = {template: `<province></province>`,components: {province}}//注册组件new Vue({el: "#app",components: { //局部注册app}}) </script> </html>
3.2.4 VueComponent
1)VueComponent是组件的构造函数,该构造函数不需要我们程序员自己调用,Vue.extend会自动调用的,可以查看源码:
var Sub = function VueComponent(options) {this._init(options); };
2)当我们编写组件标签时,Vue在解析时,会帮我们创建组件的实例对象,即Vue帮我们执行下列操作:
new VueComponent(options)。
3)每次调用Vue.extend时,返回的都是一个全新的VueComponent构造器
Vue.extend = function (extendOptions) {/* ...省略... */var Sub = function VueComponent(options) {this._init(options);};/* ...省略... */return Sub; };
4)this关键字
1. 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent的实例对象】 2. new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】
5)VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm
3.2.5 VueComponent原型链
3.3 单文件组件的开发
单文件组件的意思,就是一个组件占用一个文件,并且该文件的扩展名是.vue
。该文件里包含了HTML,JS,CSS代码,每种代码都是单独一个模块。
3.3.1单文件组件开发的步骤
第一步:创建组件文件,比如School.vue。建议文件名首字母大写
第二步:编写组件模版,并向外暴露组件。
<!-- 1. template: 书写组件的HTML布局代码 --> <template> </template> <!-- 2. script: 书写组件的交互代码 --> <script> </script> <!-- 3. style: 书写组件的CSS代码 --> <style> </style>
向外暴露有三种方式:
1. 直接暴露: 在定义组件时,直接使用export来修饰export const school = {data(){return {studentName:"水利电力学院",age:21}}} 2. 统一暴露: 可以一次性暴露多个组件export {school,.....} 3. 默认暴露:也是在定义组件时,进行暴露,格式如下:export default {name:"组件名", // 最好和文件名一致。data(){return {studentName:"水利电力学院",age:21}},//....}
第三步:定义所有组件的父组件App.vue, 引入并注册子组件,并暴露App组件
<template>
</template>
<script>
//引入School
import School from "./School.vue";
export default {
name:"App",
//注册子组件
components:{
School
}
}
</script>
<style>
</style>
第四步:定义程序入口文件main.js,引入相关组件,并定义Vue实例,配置相关选项
import App from "./App.vue" new Vue({el: "#demo",components: {App} })
第五步:定义主页面index.html。定义容器,使用组件,导入js文件
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><div id="demo"><App></App></div><script src="../../js/vue.js"></script><script src="./main.js"></script></body> </html>
3.3.2 简单案例演示
School.vue
<!-- 1. template: 书写组件的HTML布局代码 --> <template><div class="sc1"><p>学校名称:{{schoolName}}</p><p>学校地址:{{schoolAddress}}</p></div> </template> <!-- 2. script: 书写组件的交互代码 --> <script>export default{name:"School",data(){return {schoolName:"吉林大学",schoolAddress:"高新区前进大街2699号"}}} </script> <!-- 3. style: 书写组件的CSS代码 --> <style>.sc{background-color: #178167;font-style: italic;} </style>
City.vue
<!-- 1. template: 书写组件的HTML布局代码 --> <template><ul>{{cityName}}<li style="list-style: decimal;"><School/></li></ul></template><!-- 2. script: 书写组件的交互代码 --><script>import School from './School.vue'export default{name:"City",data(){return {cityName:"长春市"}},components: { School }}</script><!-- 3. style: 书写组件的CSS代码 --><style></style>
App.vue
<template><div><City></City></div> </template> <script> import City from './City.vue' export default {name:"App",components:{City} } </script> <style> </style>
main.js
import App from './App.vue' new Vue({el: "#app",components: {App} })
index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><div id="app"><App></App></div><script src="../myjs/vue.js"></script><script src="./main.js"></script> </body> </html>
单文件组织结构如下图:
案例写完了,但是运行时报错了。原因很简单, 浏览器不能直接支持es6的模块化语法…
此时,需要使用Vue的脚手架才可以。