2024.10月17日- 关于Vue2-(2)

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初始化时,就调用一次回调函数handler
      deep: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可以是字符串,对象,数组

-字符串写法适用于:类名不确定,要动态获取

-对象写法适用于:要绑定多个样式,个数确定,名字确定,但是不确定用不用

-数组写法适用于:要绑定多个样式,个数不确定,名字也不确定

  1. 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(指令名,回调函数)

  1. 配置对象中常用的3个回调函数:

bind(element,binding):指令与元素成功绑定时调用

inserted(element,binding):指令所在元素被插入页面时调用

update(element,binding):指令所在模板结构被重新解析时调用

  1. 备注:

指令定义时不加"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选项
      //创建Vue
      new 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的脚手架才可以。

相关推荐
AR7_3 分钟前
App开发Flutter支持Harmony OS Next方案
前端
聪明的墨菲特i26 分钟前
VUE组件学习 | 六、v-if, v-else-if, v-else组件
前端·vue.js·学习·前端框架·vue
Justinc.1 小时前
Flutter图片控件(七)
开发语言·flutter
Wonderful_Wan81 小时前
【前端项目工程】Uni-app 离线打包apk
前端·uni-app
木子七1 小时前
Js内建对象
前端·javascript
GDAL2 小时前
HTML入门教程2:HTML发展历史
前端·html
前端Hardy2 小时前
HTML&CSS:3D旋转动画机器人摄像头
前端·css·3d·html
WwangXue2 小时前
mac如何下载 测试旧版chrome兼容问题
前端·chrome
浏览器爱好者2 小时前
Chrome和Firefox如何保护用户的浏览数据
前端·chrome·firefox
Front思2 小时前
根据输入的详细地址解析经纬度
前端·javascript