vue学习---基于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框架的特点

  1. 组件开发,提高代码的复用率

  2. 声明式编程(更多的关注数据),以前是命令式编程,不再操作复杂的DOM树

  3. 虚拟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')

猜你喜欢

转载自blog.csdn.net/m0_53181852/article/details/127356407