VUE之旅—day1

文章目录

  • Vue概念
  • Vue实例
  • 插值表达式
  • 响应式
  • Vue指令
          • v-html
          • v-show
          • v-if
          • v-else和v-else-if
          • v-on
          • v-bind
          • v-for
          • v-model
  • 小黑记事本案例
  • 指令修饰符
  • v-bind对于样式控制的增强
          • 操作class
          • 操作style
  • v-model应用于其他表单元素
  • 计算属性
      • computed计算属性 vs methods方法
      • 计算属性的完整写法
  • watch监听器
  • 翻译小案例
  • 水果购物车案例

Vue概念

Vue 是一个用于构建用户界面渐进式 框架

  1. 构建用户界面:基于数据动态渲染页面
  2. 渐进式:循序渐进的学习
  3. 框架:一谈完整的项目解决方案,提升开发效率

Vue实例

创建Vue实例,初始化渲染

  1. 准备容器(Vue所管理的范围)
  2. 引包(官网)------开发版本/生产版本
  3. 创建Vue实例 new Vue()
  4. 指定配置项 el data=>渲染数据
    • el 指定挂载点,选择器指定控制的是哪个盒子
    • data提供数据
<body>
  <div id="app">
    <!-- 这里将来会编写一些用于渲染的代码逻辑 -->
    {{ msg }}
  </div>
  <!-- 引入的是开发版本包,包含完整的注释和警告 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    // 一旦引入VueJS核心包,在全局环境,就有了Vue构造函数
    const app = new Vue({
      // 通过el配置选择器,指定Vue管理的是哪个盒子
      el: '#app',
      // 通过data提供数据
      data: {
        msg: '我是vue的第一个实例'
      }
    })
  </script>
</body>

插值表达式

利用表达式进行插值,将数据渲染页面中

插值表达式的注意点:

  1. 使用的数据要存在
  2. 支持的是表达式,而非if…for语句
  3. 不能再标签属性里面使用

响应式

什么是响应式?

数据改变,视图自动更新

使用Vue开发---->更专注于业务核心逻辑

如何访问或修改数据?

data中的数据,最终会被添加到实例上

  1. 访问数据:“实例.属性名”
  2. 修改数据:“实例.属性名”=“值“

安装vue工具

Vue指令

指令就是带有v-前缀的特殊属性,不同属性对应不同的功能。

学习不同的指令——>解决不同业务场景需求

v-html

v-html="表达式"——>动态设置元素innerHTML

<body>
  <div id="app">
    <div v-html="msg"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        msg: `<a href="https://www.csdn.net/">CSDN官网</a> `
      }
    })
  </script>
</body>
v-show
  1. 控制元素显示隐藏
  2. v-show="表达式",表达式值true显示,false隐藏
  3. 原理:切换display:none来控制显示隐藏
  4. 场景:频繁切换显示隐藏的场景
v-if
  1. 控制元素的显示隐藏(条件渲染)
  2. 语法:v-if="表达式",表达式值true显示,false隐藏
  3. 原理:基于条件判断,是否创建或移除元素节点
  4. 场景:要么显示,要么隐藏,不频繁切换场景

v-showv-if的区别

  • v-show底层原理:切换css的display:none来控制显示隐藏(通常称为简单的显示和隐藏)
  • v-if底层原理:根据判断条件控制元素的创建和移除(通常称为条件渲染)
<body>
  <div id="app">
    <div v-show="flag" class="box">
      我是v-show控制的盒子
    </div>
    <div v-if="flag" class="box">
      我是v-if控制的盒子
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        flag: false
      }
    })
  </script>
</body>

v-else和v-else-if
  1. 辅助v-if进行判断 渲染
  2. 语法:v-else v-else-if="表达式"
  3. 注意:需要紧挨着v-if 一起使用
<body>
  <div id="app">
    <h1 v-if="gender===1">性别:男</h1>
    <h1 v-else>性别:女</h1>
    <p v-if="score>=90">成绩评定A</p>
    <p v-else-if="score>=70&&score<90">成绩评定B</p>
    <p v-else-if="score>=60&&score<70">成绩评定C</p>
    <p v-else>成绩评定D</p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        gender: 1,
        score: 89
      }
    })
  </script>
</body>
v-on
  1. 注册事件=添加监听+提供处理逻辑
  2. 语法:
    • v-on:事件名=“内联语句"
    • v-on:事件名=“Methods”中的函数名
  3. 简写:@事件名
  4. methods函数内的this指向Vue实例
<body>
  <div id="app">
    <button @click="count--">-</button>
    <span>{{count}}</span>
    <button @click="count++">+</button>
    <hr>
    <!-- 华丽的分割线 -->
    <button @click="fn">显示与隐藏</button>
    <h1 v-show="flag">VUE实例</h1>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        count: 100,
        flag: true
      },
      methods: {
        fn() {
          console.log(this === app);
          this.flag = !this.flag;
        }
      }
    })
  </script>
</body>
v-bind
  1. 动态设置html的标签属性——>src url title…
  2. v-bind:属性名=“表达式”
  3. 简写形式 :属性名="表达式"
<body>
  <div id="app">
    <img :src='imgUrl' :title='msg' alt="">
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        imgUrl: './avator.jpg',
        msg: `我是一个女生`
      }
    })
  </script>
</body>
v-for
<body>
  <div id="app">
    <h1>小黑的书架</h1>
    <ul>
      <li v-for="(item,index) in booksList" :key="item.id">
        <span>{{item.name}}</span>
        <span>{{item.author}}</span>
        <button @click="del(item.id)">删除</button>
      </li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        booksList: [
          { id: 1, name: '《红楼梦》', author: '曹雪芹' },
          { id: 2, name: '《西游记》', author: '吴承恩' },
          { id: 3, name: '《水浒传》', author: '施耐庵' },
          { id: 4, name: '《三国演义》', author: '罗贯中' }
        ]
      },
      methods: {
        del(id) {
          this.booksList = this.booksList.filter(item => item.id !== id)
        }
      }
    })
  </script>
</body>

**:key="item.id"**的作用分析:

给元素添加唯一的表示,便于Vu进行列表项的正确排序复用

  1. key 的值只能是字符串或数字类型
  2. key值必须有唯一性
  3. 推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)
v-model
  1. 作用:给表单元素使用,双向数据绑定——>可以快速获取和设置表单元素内容
    • 数据变化——>视图自动更新
    • 视图变化——>数据自动更新
  2. 语法:v-model=‘变量’

小黑记事本案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>小黑记事本</title>
  <link rel="stylesheet" href="./diray.css">
</head>
<body>
  <section id="app">
    <header class="header">
      <h1>小黑记事本</h1>
      <div class="header-input">
        <input v-model="todoName" type="text" placeholder="请添加任务">
        <button @click="add()" id="addThing">添加任务</button>
      </div>
    </header>
    <section class="main">
      <ul class="todo-list">
        <li class="todo" v-for="(item,index) in list" :key="item.id">
          <div class="view">
            <span>{{index+1}}.</span>
            <span>{{item.thing}}</span>
            <span class="del" @click="del(item.id)">X</span>
          </div>
        </li>

      </ul>
    </section>
    <footer class="footer" v-show="list.length>0">
      <span class="todo-count">合计:<strong>{{list.length}}</strong></span>
      <button class="clearAll" @click="clear()">
        清空任务
      </button>
    </footer>
  </section>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    document.addEventListener('keyup', function (e) {
      if (e.keyCode === 13) {
        app.add()
      }
    })
    const app = new Vue({
      el: '#app',
      data: {
        todoName: '',
        list: [
          { id: 1, thing: '跑步3km' },
          { id: 2, thing: '游泳3km' },
          { id: 3, thing: '跳绳200次' },
        ]
      },
      methods: {
        del(id) {
          this.list = this.list.filter(item => item.id !== id)
        },
        add() {
          if (this.todoName.trim() === '') {
            alert('请输入任务名称')
            return
          }
          this.list.unshift({
            id: +new Date(),
            thing: this.todoName
          })
          this.todoName = ''
        },
        clear() {
          this.list = []
        }
      }
    })
  </script>
</body>
</html>
#app {
  width: 500px;
  margin: 0 auto;
  color: #858080;
  background-color: #ffffff;
  padding: 10px 0;
  box-shadow: 0px 0px 5px #a3a1a1;
}

#app header h1 {
  text-align: center;
  font-size: 38px;
  font-weight: 100;
  color: #b85959;
  margin: 10px 0;
}

#app header .header-input {
  width: 410px;
  height: 40px;
  margin: 0 auto;
  padding: 20px 10px;
  position: relative;
}

#app header .header-input input {
  width: 400px;
  height: 40px;
  outline: none;
  font-size: 16px;
  border: none;
  border: 1px solid #be2727;
  border-radius: 8px;
  text-indent: 10px;
}

#app header .header-input button {
  width: 80px;
  height: 44px;
  position: absolute;
  right: 10px;
  top: 20px;
  border: none;
  color: #eee6e6;
  background-color: #d15959;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  cursor: pointer;
}

#app .main .todo-list {
  margin: 0;
  padding: 0;
  list-style: none;
  width: 430px;
  margin: 0 auto;
}

#app .main .todo {
  margin: 0 auto;
  height: 50px;
  width: 95%;
  line-height: 50px;
  border-bottom: 1px solid #c3bebe;
  position: relative;
}

#app .main .todo span {
  display: inline-block;
  margin: 0 12px;
  font-size: 18px;
}

#app .main .todo .del {
  position: absolute;
  right: 10px;
  cursor: pointer;
  font-weight: bolder;
  display: none;
}

#app .main .todo .del:hover {
  color: #c35c5c;
}

#app .main .todo:hover .del {
  display: inline-block;
}

#app footer {
  width: 410px;
  padding: 10px 10px;
  height: 30px;
  margin: 0 auto;
  font-size: 12px;
  display: flex;
  justify-content: space-between;
}

#app footer span {
  display: inline-block;
  height: 30px;
  line-height: 30px;
}

#app footer button {
  color: #858080;
  border: none;
  background-color: #ffffff;
  cursor: pointer;
}

#app footer button:hover {
  color: #a73535;
  text-decoration: underline;
}

指令修饰符

通过.指明一些指令后缀,不同后缀封装了不同的处理操作—>简化代码

  1. 按键修饰符

    @keyup.enter —>键盘回车监听

  2. v-model修饰符

    v-model.trim —>去除首尾空格

    v-model-number —>转数字

  3. 事件修饰符

    @事件名.stop —>阻止冒泡

    @事件名.prevent —>组织默认行为

v-bind对于样式控制的增强

操作class

语法::class="对象/数组"

  1. 对象—>键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类

    <div class="box" :class="{类名1:布尔值,类名2:布尔值}"></div>
    
  2. 数组—>数组中所有的类,都会添加到盒子上,本质上就是一个class列表

    <div class="box" :class="[类名1,类名2,类名3]"></div>
    
操作style

语法::style="样式对象"

 <div class="box" :style="{css属性名1:css属性值1,css属性名2:css属性值2}"></div>

v-model应用于其他表单元素

常见的表单元素都可以用v-model绑定关联—>快速获取或设置表单的值,它会根据控件类型自动选取正确的方法来更新元素

输入框 input:text —>value

文本域 textarea —>value

复选框 input:checkbox —>checked

单选框 input:text —>checked

下拉菜单 select —>value

<body>
  <div id="app">
    <h1>小黑学习网</h1>

    姓名:
    <input type="text" v-model="username">
    <br><br>

    是否单身:
    <input type="checked" v-model="IsSingle">
    <br><br>

    <!-- 理解:
        1.name:给单选框加上name属性 可以分组->同一组互相会互斥
        2.value:给单选框加上value属性,用于提交给后台的数据
        结合Vue使用->v-model
    -->
    性别:
    <input type="radio" name="sex" v-model="gender" value="1"><input type="radio" name="sex" v-model="gender" value="2"><br><br>

    <!-- 理解:
          1.option需要设置value值,提交给后台
          2.select的value值,关联选中的option的value值
          结合Vue使用->v-model
    -->
    所在城市:
    <select v-model="city">
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">成都</option>
      <option value="104">南京</option>
    </select>
    <br><br>

    自我描述:
    <textarea v-model="desc"></textarea>
    <br><br>

    <button>立即注册</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '小黑',
        IsSingle: true,
        gender: 2,
        city: 103,
        desc: '爱好文学'
      }
    })
  </script>
</body>

计算属性

**概念:**基于现有数据,计算出来的新属性。依赖的数据变化,自动重新计算。

语法:

  1. 声明在computed配置项中,一个计算属性对应一个函数
  2. 使用起来和普通属性一样使用{{计算属性名}}

计算属性—>可以将一段求值代码进行封装

computed计算属性 vs methods方法

computed计算属性

作用:封装了一段对于数据的处理,求得一个结果。

语法:

  1. 写在computed配置项中
  2. 作为属性,直接使用—>this.计算属性 {{计算属性}}

methods方法

作用:给实例提供一个方法,调用以处理业务逻辑

语法:

  1. 写在methods配置项中
  2. 作为方法,需要调用—>this.方法名() {{方法名()}} @事件名=“方法名”

computed计算属性有缓存特性(提升性能)

计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖变化了,会自动重新计算—>并再次缓存

计算属性的完整写法

计算属性默认的简写,只能读取访问,不能“修改”。

如果要“修改”—>需要写计算属性的完整写法

computed:{
	计算属性名:{
	get(){
		一段代码逻辑(计算逻辑)
		return 结果
	},
	set(修改的值){
		一段代码逻辑(修改逻辑)
	}
	}
}

watch监听器

作用:监视数据变化

语法:

  • 简单写法:简单类型数据,直接监视
 const app = new Vue({
      el: '#app',
      data: {
        words: '苹果',
        obj: {
          words: '苹果'
        }
      },
      watch: {
        words(newValue, oldValue) {
          // 一些业务逻辑 或者 异步操作
        },
        'obj.words'(newValue, oldValue) {
          // 一些业务逻辑 或者 异步操作
        }
      }
    })
  • 完整写法:添加额外配置项(深度监视复杂类型,立刻执行)
watch: {
  数据属性名:{
       deep: true,//深度监视
          immediate: true,//立刻执行,已进入页面就立刻执行
          handler(newValue) {
              console.log(newValue)
          }
  }
}

翻译小案例

  1. 接口传参
  2. 防抖优化
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>小小翻译器</title>
  <style>
    #app {
      width: auto;
    }

    .translate {
      display: flex;
    }

    .text {
      width: 180px;
      height: 150px;
      font-size: 20px;
      border: 1px solid #838383;
      padding: 20px;
      color: #2f2e2e;
    }

    .text textarea {
      width: 95%;
      height: 95%;
      resize: none;
      outline: none;
      border: none;
      font-size: 20px;

    }

    #outText {
      border: none;
      background-color: #e6e6e6;
    }
  </style>
</head>

<body>
  <div id="app">
    <span>翻译成的语言:</span>
    <select v-model="obj.lang">
      <option value="italy">意大利</option>
      <option value="english">英语</option>
      <option value="german">德语</option>
    </select>
    <div class="translate">
      <div class="text">
        <textarea type="text" placeholder="输入文本" v-model="obj.words" id="inText"></textarea>
      </div>
      <div class="text" id="outText">
        <div type="text" placeholder="翻译">{{ result }}</div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        result: '',
        // timer: null,
        //这个属性无需渲染,用来做防抖优化,可以直接需要使用时挂载到app对象身上
        obj: {
          lang: 'italy',
          words: ''
        }
      },
      watch: {
        obj: {
          deep: true,//深度监视
          immediate: false,//立刻执行,已进入页面就立刻执行
          handler(newValue) {
            //防抖优化
            clearTimeout(this.timer)
            // this.timer 直接将timer属性挂载到app对象身上
            this.timer = setTimeout(async () => {
              const res = await axios({
                //接口说明:
                // 接口地址:https://applet-base-api-t.itheima.net/api/translate
                // 接口是随机返回 一个字符串
                // 请求方式:get
                // 请求参数
                // (1)words:需要被翻译的文本(必传)
                // (1)lang:需要被翻译成的语言(可选)默认值 意大利
                // 
                url: 'https://applet-base-api-t.itheima.net/api/translate',
                //请求方式get可以省略不写
                params: newValue
              })
              this.result = res.data.data
            }, 900)
          }
        }
      }
    })
  </script>
</body>

</html>

水果购物车案例

需求说明:

  1. 渲染功能
  2. 删除功能
  3. 修改个数
  4. 全选反选
  5. 统计选中的总价和总数量
  6. 持久化到本地

业务实现

  1. 渲染功能:v-if/v-show v-for :class
  2. 删除功能:点击传参 filter过滤覆盖原数组
  3. 修改个数:点击传参 find找对象
  4. 全选反选:计算属性computed 完整写法get/set
  5. 统计选中的总价和总数量:计算属性computed reduce条件求和
  6. 持久化到本地:watch监视,localStorage JSON.stringify JSON.parse
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>水果购物车</title>
  <style>
    .app-container {
      width: 720px;
      height: auto;
      margin: 0 auto;
    }

    .banner {
      width: 100%;
      height: 100%;
    }

    .banner img {
      width: 100%;
      height: 100%;
    }

    .main .table {
      width: 100%;
      height: auto;
      border-collapse: collapse;
    }

    .empty {
      width: 100%;
      height: 100px;
      font-size: 24px;
      color: #575757;
      line-height: 100px;
      text-align: center;
      background-color: #f7f7f7;

    }

    .main .table .tr {
      height: 100%;
      display: flex;
      border: 1px solid #e8e7e7;
      justify-content: space-around;
      text-align: center;
    }

    .main .table .tbody .active {
      background-color: #f3f3f3;
    }

    .main .table .tr .th,
    .td {
      width: 120px;
      height: 80px;
      box-sizing: border-box;
      text-align: center;
      color: #575757;
    }

    .main .table .thead {
      background-color: #f7f5f5;
      height: 50px;
      line-height: 50px;
    }

    .main .table .tbody .td {
      line-height: 80px;
      font-size: 16px;

    }

    .main .table .tbody .td img {
      width: 80px;
      height: 80px;
      margin: 0 auto;
    }

    .main .table .tbody .td input {
      cursor: pointer;
    }

    .main .table .tbody .number-op {
      width: 120px;
      height: 40px;
      display: flex;
      justify-content: center;
      text-align: center;
      margin: 20px auto;
      box-shadow: 0 0 5px #818181;
    }

    .main .table .tbody .number-op .sub,
    .add {
      height: 100%;
      line-height: 40px;
      width: 40px;
      background-color: #f1f1f1;
      border: none;
      outline: none;
      cursor: pointer;
    }

    .main .table .tbody .number-op .number {
      width: 55px;
      height: 100%;
      line-height: 40px;
      background-color: #fefefe;
    }

    .main .table .tbody .tr .delelte button {
      width: 60px;
      height: 30px;
      line-height: 30px;
      background-color: #fc4f4f;
      color: #FFF;
      margin: 20px auto;
      border-radius: 4px;
      font-size: 12px;
      outline: none;
      border: none;
      cursor: pointer;
    }

    .main .bottom {
      width: 100%;
      height: 60px;
      line-height: 60px;
      border: 1px solid #e8e7e7;
    }

    .main .bottom .checkAll,
    .total {
      width: 60%;
      display: inline-block;
      text-indent: 50px;
    }

    .main .bottom .total {
      width: 25%;
      display: inline-block;
    }

    .main .bottom .total span {
      color: rgb(251, 135, 152);
      font-size: 30px;
      font-weight: bold;
    }

    .main .bottom button {
      width: 80px;
      height: 35px;
      border: none;
      background-color: #5689bc;
      color: #fff;
      border-radius: 4px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner"><img src="https://img.tukuppt.com/bg_grid/00/03/63/pd1Ab79ETa.jpg!/fh/350" alt=""></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">主页/购物车</div>
    <!-- 购物车主体 -->
    <div class="main" v-if="fruitList.length>0">
      <div class="table">
        <!-- 头部 -->
        <div class="thead">
          <div class="tr">
            <span class="th">选中</span>
            <span class="th">图片</span>
            <span class="th">单价</span>
            <span class="th">个数</span>
            <span class="th">小计</span>
            <span class="th">操作</span>
          </div>
        </div>
        <!-- 身体 -->
        <div class="tbody">
          <div class="tr" v-for="(item,index) in fruitList" :key="item.id" :class="{active:item.isChecked}">
            <div class="td"><input type="checkbox" v-model="item.isChecked"></div>
            <div class="td"><img :src="item.icon" alt="加载失败"></div>
            <div class="td">{{item.price}}</div>
            <div class="td number-op">
              <button class="sub" :disabled="item.num<=1" @click="sub(item.id)">-</button>
              <div class="number">{{item.num}}</div>
              <button class="add" @click="add(item.id)">+</button>
            </div>
            <div class="td">{{item.num*item.price }}</div>
            <div class="td delelte"><button @click="del(item.id)">删除</button></div>
          </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">
          <div class="checkAll"><input type="checkbox" v-model="isAll">全选</div>
          <div class="total">总价:¥<span>{{totalPrice}}</span></div>
          <button>结算(<span>{{totalCount}}</span>)</button>
        </div>
      </div>
    </div>
    <!-- 空车 -->
    <div class="empty" v-else>
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-cart"
        viewBox="0 0 16 16">
        <path
          d="M0 1.5A.5.5 0 0 1 .5 1H2a.5.5 0 0 1 .485.379L2.89 3H14.5a.5.5 0 0 1 .491.592l-1.5 8A.5.5 0 0 1 13 12H4a.5.5 0 0 1-.491-.408L2.01 3.607 1.61 2H.5a.5.5 0 0 1-.5-.5zM3.102 4l1.313 7h8.17l1.313-7H3.102zM5 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm7 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm-7 1a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm7 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" />
      </svg> 空空如也
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // fruitList: [
        //   {
        //     id: 1,
        //     // 草莓
        //     icon: 'https://bpic.588ku.com/element_origin_min_pic/19/03/07/e2a9f2049f8a27a802adc898a9a77263.jpg',
        //     isChecked: true,
        //     num: 2,
        //     price: 6,
        //   },
        //   {
        //     id: 2,
        //     //橘子
        //     icon: 'https://ts1.cn.mm.bing.net/th/id/R-C.cc043de924afe4c8e339ac9153fc6d0a?rik=idAViLjhl02Pkw&riu=http%3a%2f%2fimg95.699pic.com%2felement%2f40114%2f0063.png_860.png&ehk=%2bswafoP2gLwU6isZhlfWUgCDGnXxHt00KH1VlPG%2f3FI%3d&risl=&pid=ImgRaw&r=0',
        //     isChecked: true,
        //     num: 3,
        //     price: 6,
        //   },
        //   {
        //     id: 3,
        //     // 葡萄
        //     icon: 'https://tse2-mm.cn.bing.net/th/id/OIP-C.IE5_7TEOtuDLzOWoWmIevQHaFP?w=280&h=198&c=7&r=0&o=5&dpr=1.8&pid=1.7',
        //     isChecked: true,
        //     num: 2,
        //     price: 5,
        //   },
        //   {
        //     id: 4,
        //     // 西瓜
        //     icon: 'https://tse1-mm.cn.bing.net/th/id/OIP-C.j5_OeK8DBQLiq6PSHsh_bwHaHa?w=197&h=198&c=7&r=0&o=5&dpr=1.8&pid=1.7',
        //     isChecked: true,
        //     num: 2,
        //     price: 5,
        //   },
        //   {
        //     id: 5,
        //     //水蜜桃
        //     icon: 'https://tse1-mm.cn.bing.net/th/id/OIP-C.cJAO-NexLdDrjFm_TtOWvgHaHa?w=193&h=194&c=7&r=0&o=5&dpr=1.8&pid=1.7',
        //     isChecked: true,
        //     num: 8,
        //     price: 6,
        //   },
        //   {
        //     id: 6,
        //     // 苹果
        //     icon: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.3sFMitLegnrn_6OOGf6drQHaHa?rs=1&pid=ImgDetMain',
        //     isChecked: true,
        //     num: 2,
        //     price: 6,
        //   },
        //   {
        //     id: 7,
        //     // 荔枝
        //     icon: 'https://tse1-mm.cn.bing.net/th/id/OIP-C.zy_tCKWr8TxhJbG_ZZpFbQHaHa?w=210&h=210&c=7&r=0&o=5&dpr=1.8&pid=1.7',
        //     isChecked: true,
        //     num: 2,
        //     price: 6,
        //   },
        // ]
        // 取数据的时候去的是本地浏览器保存的数据
        fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
      },
      methods: {
        del(id) {
          this.fruitList = this.fruitList.filter(item => item.id !== id)
        },
        add(id) {
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.num++
        },
        sub(id) {
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.num--
        }
      },
      computed: {
        // 完整写法:set+get 
        isAll: {
          get() {
            return this.fruitList.every(item => item.isChecked)
          },
          set(value) {
            // 同步小选框和全选框的状态
            this.fruitList.forEach(item => item.isChecked = value)
          }
        },
        totalCount() {
          return this.fruitList.reduce((sum, item) =>
            item.isChecked ? sum + item.num : sum
            , 0)
        },
        totalPrice() {
          return this.fruitList.reduce((sum, item) =>
            item.isChecked ? sum + item.num * item.price : sum
            , 0)
        }
      },
      watch: {
        fruitList: {
          deep: true,
          handler(newValue) {
            // 一旦修改,就将新数据存入浏览器本地中
            localStorage.setItem('list', JSON.stringify(newValue))
          }
        }
      }
    })
  </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/570543.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【智能算法】指数分布优化算法(EDO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2023年&#xff0c;M Abdel-Basset等人受到指数分布理论启发&#xff0c;提出了指数分布优化算法&#xff08;Exponential Distribution Optimizer, EDO&#xff09;。 2.算法原理 2.1算法思想 ED…

mac系统镜像源管理之nrm的安装与使用

之前有介绍过&#xff1a;pnpm安装和使用&#xff0c;nvm安装及使用&#xff0c;在前端开发中其实还有一个工具也会偶尔用到&#xff0c;那就是nrm&#xff0c;本文就详解介绍一下这个工具&#xff0c;非常的简单且好用&#xff5e; 文章目录 1、什么是nrm&#xff1f;2、安装3…

CPU资源控制

一、CPU资源控制定义 cgroups&#xff08;control groups&#xff09;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 所以cgroups&#xff08;control groups&#xf…

【IC设计】奇数分频与偶数分频 电路设计(含讲解、RTL代码、Testbench代码)

文章目录 原理分析实现和仿真偶数分频的电路RTL代码偶数分频的电路Testbench代码偶数分频的电路仿真波形占空比为50%的三分频电路RTL代码占空比为50%的三分频电路Testbench代码占空比为50%的三分频电路仿真波形 参考资料 原理分析 分频电路是将给定clk时钟信号频率降低为div_c…

Springboot 整合 Quartz框架做定时任务

在Spring Boot中整合Quartz&#xff0c;可以实现定时任务调度的功能 1、首先&#xff0c;在pom.xml文件中添加Quartz和Spring Boot Starter Quartz的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-bo…

基于MNIST的手写数字识别

上次我们基于CIFAR-10训练一个图像分类器&#xff0c;梳理了一下训练模型的全过程&#xff0c;并且对卷积神经网络有了一定的理解&#xff0c;我们再在GPU上搭建一个手写的数字识别cnn网络&#xff0c;加深巩固一下 步骤 加载数据集定义神经网络定义损失函数训练网络测试网络 …

AI绘画怎么用涂抹消除处理图片?

AI绘画软件中的涂抹消除功能通常用于处理图片&#xff0c;以去除不需要的部分或进行细节调整。不同的AI绘画软件可能具有不同的界面和功能设置&#xff0c;因此具体的操作步骤可能会有所不同。那么AI绘画一般怎么用涂抹消除处理图片? 该功能主打“一键消除&#xff0c;不留痕迹…

【MCU】栈溢出问题

项目场景&#xff1a; 硬件&#xff1a;STM32F407&#xff0c;操作系统&#xff1a;rt_thread master分支 问题描述 问题栈溢出 id 499 ide 00 rtr 00 len 8 9 Function[rt_completion_wait] shall not be used in ISR (0) assertion failed at function:rt_completion_wait,…

由于磁盘空间不够导致服务无法访问的情况

昨天服务出现了一些“小状况”&#xff0c;这里做下记录&#xff0c;为了以后类似的问题&#xff0c;可以作为参考。 具体情况是&#xff0c;如下&#xff1a; 本来一直访问都好好的服务突然间访问不到了&#xff0c;首先确定了下服务器上的 docker 服务是否正常运行。确认正…

粒子群算法与优化储能策略python实践

粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;, 是1995年J. Kennedy博士和R. C. Eberhart博士一起提出的&#xff0c;它是源于对鸟群捕食行为的研究。粒子群优化算法的基本核心是利用群体中的个体对信息的共享从而使得整个群体的运动…

【办公类-26-01】20240422 UIBOT网络教研(自动登录并退出多个账号,半自动半人工)

作品展示&#xff1a; 背景需求&#xff1a; 每学期有多次网络教研 因为我有历任搭档的进修编号和登录密码&#xff0c; 所以每次学习时&#xff0c;我会把历任搭档的任务也批量完成。 但是每次登录都要从EXCEL里复制一位老师的“进修编号”“密码”&#xff0c;还要点击多次…

快速回复app是什么样

在电商领域&#xff0c;掌握一些必备的软件工具是提高工作效率、优化运营流程以及提升用户体验的关键。本文将为您介绍做电商必备的几个软件&#xff0c;帮助您更好地开展电商业务。 ​ 快速回复APP&#xff1a;重新定义沟通效率 在快节奏的现代社会中&#xff0c;人们对于沟通…

53.基于微信小程序与SpringBoot的戏曲文化系统设计与实现(项目 + 论文)

项目介绍 本站采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的戏曲文化系统设计与实现管理工作系统化、规范化。 技术选型 后端:…

Aigtek功率放大器的工作特点有哪些方面

功率放大器是电子设备中常见的元器件&#xff0c;用于将输入信号的功率增加到所需的输出功率水平。它在各种应用中发挥着重要作用&#xff0c;如音频放大、射频信号处理、通信系统等。功率放大器具有以下几个工作特点&#xff1a; 放大功能&#xff1a;功率放大器主要的工作特点…

用户请求经过哪些处理(公网)

DNS服务器之间协作&#xff1a; 递归DNS查询&#xff1a;用户的请求首先发送到递归DNS服务器。 查询根DNS服务器&#xff1a;递归DNS服务器查询根DNS服务器&#xff0c;以找到管理.com顶级域的TLD DNS服务器。 查询TLD DNS服务器&#xff1a;根DNS服务器响应带有TLD DNS服务器…

深入Doris实时数仓:导入本地数据

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! < 免责声明 > 避免对文章进行过度解读&#xff0c;因为每个人的知识结构和认知背景不大同&#xff0c;没有一种通用的解决方…

【Java探索之旅】解密构造方法 对象初始化的关键一步

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、对象的构造及初始化1.1 构造方法1.2 构造方法的特性1.3 默认初始化1.4 就地初始化…

新手可以能做视频号小店,其实,视频号远没你想象中难!

大家好&#xff0c;我是电商花花。 最近注意到一个又一个新手小白提供视频号小店成功逆袭&#xff0c;实现了自己的创业梦想。 最近电商行业在飞速发展&#xff0c;越来越多的人开始关注视频号小店这个新兴的市场和平台。 有的新手拼命的往里扎&#xff0c;但是不少新手商家…

数据库之数据库恢复技术思维导图+大纲笔记

大纲笔记&#xff1a; 事务的基本概念 事务 定义 用户定义的一个数据库操作系列&#xff0c;这些操作要么全做&#xff0c;要么全不做&#xff0c;是一个不可分割的基本单位 语句 BEGIN TRANSACTION 开始 COMMIT 提交&#xff0c;提交事务的所有操作 ROLLBACK 回滚&#xff0c…

UE5 GAS开发P35,36,37,38,39 将药水修改为AbilitySystem效果

这几节课都是将药水修改成更方便使用的AbilitySystem效果的Actor,分别为增加血量,增加蓝量,暂时获得最大生命值上限 AuraEffectActor.h // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #…
最新文章