day02

指令

@keyup.enter 回车

<div id="app">
    <h3>@keyup.enter  →  监听键盘回车事件</h3>
    <input @keyup.enter="fn" v-model="username" type="text">
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: ''
      },
      methods: {
        fn (e) {
          // if (e.key === 'Enter') {
          //   console.log('键盘回车的时候触发', this.username)
          // }
          console.log('键盘回车的时候触发', this.username)
        }
      }
    })
  </script>

v-model修饰符 .trim .number

<div id="app">
    <h3>v-model修饰符 .trim .number</h3>
    姓名:<input v-model.trim="username" type="text"><br>
    年纪:<input v-model.number="age" type="text"><br>

    
    <h3>@事件名.stop     →  阻止冒泡</h3>
    <div @click="fatherFn" class="father">
      <div @click.stop="sonFn" class="son">儿子(点击儿子不会弹出父亲得提示)</div>
    </div>

    <h3>@事件名.prevent  →  阻止默认行为</h3>
    <a @click.prevent href="http://www.baidu.com">阻止默认行为(点击a标签不会跳转)</a>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        age: '',
      },
      methods: {
        fatherFn () {
          alert('老父亲被点击了')
        },
        sonFn (e) {
          // e.stopPropagation()
          alert('儿子被点击了')
        }
      }
    })
  </script>

v-bind对样式class的控制

<div id="app">
    <div class="box" :class="{ pink: true, big: false }">黑马程序员(大括号会看后面的布尔值)</div>
    <div class="box" :class="['pink', 'big']">黑马程序员(中括号里面的属性都会生效)</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>

v-bind对样式style的控制

<div id="app">
    <div class="box" :style="{ width: '400px', height: '400px', backgroundColor: 'green' }"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>

v-bind 记得加 “” :xxx=“{}[]”

tab栏的active效果

<div id="app">
    <ul>
      <li v-for="(item, index) in list" :key="item.id" @click="activeIndex = index">
        <a :class="{ active: index === activeIndex }" href="#">{{ item.name }}</a>
      </li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex: 2, // 记录高亮
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]
      }
    })
  </script>

在这里插入图片描述

进度条

 <div id="app">
    <!-- 外层盒子底色 (黑色) -->
    <div class="progress">
      <!-- 内层盒子 - 进度(蓝色) -->
      <div class="inner" :style="{ width: percent + '%' }">
        <span>{{ percent }}%</span>
      </div>
    </div>
    <button @click="percent = 25">设置25%</button>
    <button @click="percent = 50">设置50%</button>
    <button @click="percent = 75">设置75%</button>
    <button @click="percent = 100">设置100%</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        percent: 30
      }
    })
  </script>

在这里插入图片描述

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

<div id="app">
    <h3>旭哥学习网</h3>

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

    是否单身:
      <input type="checkbox" v-model="isSingle"> 
      <br><br>

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

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

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

    <button>立即注册</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        isSingle: false,
        gender: "2",
        cityId: '102',
        desc: ""
      }
    })
  </script>

在这里插入图片描述

计算属性

<!-- 计算属性可以缓存 -->
<div id="app">
    <h3>旭哥的礼物清单</h3>
    <table>
        <tr>
            <th>名字</th>
            <th>数量</th>
        </tr>
        <tr v-for="(item, index) in list" :key="item.id">
            <td>{{ item.name }}</td>
            <td>{{ item.num }}个</td>
        </tr>
    </table>

    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数:{{ totalCount }} 个</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            // 现有的数据
            list: [
                {id: 1, name: '篮球', num: 1},
                {id: 2, name: '玩具', num: 2},
                {id: 3, name: '铅笔', num: 5},
            ]
        },
        computed: {
            totalCount() {
                // 基于现有的数据,编写求值逻辑
                // 计算属性函数内部,可以直接通过 this 访问到 app 实例

                // 需求:对 this.list 数组里面的 num 进行求和 → reduce
                let total = this.list.reduce((sum, item) => sum + item.num, 0)
                return total
            }
        }
    })
</script>

在这里插入图片描述

<div id="app">
    姓:<input type="text" v-model="firstName"> +
    名:<input type="text" v-model="lastName"> =
    <span>{{ fullName }}</span><br><br>
    
    <button @click="changeName">改名卡</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        firstName: '刘',
        lastName: '备',
      },
      methods: {
        changeName () {
          this.fullName = '黄忠'
        }
      },
      computed: {
        // 简写 → 获取,没有配置设置的逻辑
        // fullName () {
        //   return this.firstName + this.lastName
        // }

        // 完整写法 → 获取 + 设置
        fullName: {
          // (1) 当fullName计算属性,被获取求值时,执行get(有缓存,优先读缓存)
          //     会将返回值作为,求值的结果
          get () {
            return this.firstName + this.lastName
          },
          // (2) 当fullName计算属性,被修改赋值时,执行set
          //     修改的值,传递给set方法的形参value
          set (value) {
            this.firstName = value.slice(0, 1)
            this.lastName = value.slice(1)
          }
        }
      }
    })
  </script>

在这里插入图片描述

计算属性完整写法 get() + set() 方法都要有

上面知识的小案例

<div id="app" class="score-case">
    <div class="table">
        <table>
            <thead>
            <tr>
                <th>编号</th>
                <th>科目</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody v-if="list.length > 0">
            <tr v-for="(item,index) in list" :key="item.id">
                <td>{{index + 1}}</td>
                <td>{{item.subject}}</td>
                <!--  :class="{}[]"  记得加  ""  -->
                <td :class="{ red: item.score < 60}">{{item.score}}</td>
                <td><a @click.prevent="del(item.id)" href="#">删除</a></td>
            </tr>
            </tbody>
            <tbody v-else>
            <tr>
                <td colspan="5">
                    <span class="none">暂无数据</span>
                </td>
            </tr>
            </tbody>

            <tfoot>
            <tr>
                <td colspan="5">
                    <span>总分:{{totalScore}}</span>
                    <span style="margin-left: 50px">平均分:{{avgScore}}</span>
                </td>
            </tr>
            </tfoot>
        </table>
    </div>
    <div class="form">
        <div class="form-item">
            <div class="label">科目:</div>
            <div class="input">
                <input
                        v-model.trim="subject"
                        type="text"
                        placeholder="请输入科目"
                />
            </div>
        </div>
        <div class="form-item">
            <div class="label">分数:</div>
            <div class="input">
                <input
                        v-model.number="score"
                        type="text"
                        placeholder="请输入分数"
                />
            </div>
        </div>
        <div class="form-item">
            <div class="label"></div>
            <div class="input">
                <button @click="add(subject,score)" class="submit">添加</button>
            </div>
        </div>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<script>
    const app = new Vue({
        el: '#app',
        data: {
            list: [
                {id: 1, subject: '语文', score: 20},
                {id: 7, subject: '数学', score: 99},
                {id: 12, subject: '英语', score: 70},
            ],
            subject: '',
            score: ''
        },
        methods: {
            del(id) {
                this.list = this.list.filter(item => item.id !== id)
            },
            add(subject, score) {
                if (!this.subject) {
                    alert('请输入科目')
                    return
                }
                if (typeof this.score !== 'number') {
                    alert('请输入正确的成绩')
                    return
                }
                this.list.unshift({
                    id: new Date(),
                    subject: subject,
                    score: score
                })
                this.subject = ''
                this.score = ''
            }
        },
        computed: {
            totalScore() {
                return this.list.reduce((sum, item) => sum + item.score, 0)
            },
            avgScore() {
                if(this.list.length === 0){
                    return 0
                }
                // toFixed 保留小数
                return (this.totalScore/this.list.length).toFixed(2)
            }
        }
    })
</script>

watch侦听器

简单写法

<div id="app">
      <!-- 条件选择框 -->
      <div class="query">
        <span>翻译成的语言:</span>
        <select>
          <option value="italy">意大利</option>
          <option value="english">英语</option>
          <option value="german">德语</option>
        </select>
      </div>

      <!-- 翻译框 -->
      <div class="box">
        <div class="input-wrap">
          <textarea v-model="obj.words"></textarea>
          <span><i>⌨️</i>文档翻译</span>
        </div>
        <div class="output-wrap">
          <div class="transbox">{{ result }}</div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
          // words: ''
          obj: {
            words: ''
          },
          result: '', // 翻译结果
          // timer: null // 延时器id
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          // 该方法会在数据变化时调用执行
          // newValue新值, oldValue老值(一般不用)
          // words (newValue) {
          //   console.log('变化了', newValue)
          // }

          'obj.words' (newValue) {
            // console.log('变化了', newValue)
            // 防抖: 延迟执行 → 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
            clearTimeout(this.timer)
            this.timer = setTimeout(async () => {
              const res = await axios({
                url: 'https://applet-base-api-t.itheima.net/api/translate',
                params: {
                  words: newValue
                }
              })
              this.result = res.data.data
              console.log(res.data.data)
            }, 300)
          }
        }
      })
    </script>

完整写法

    <div id="app">
      <!-- 条件选择框 -->
      <div class="query">
        <span>翻译成的语言:</span>
        <select v-model="obj.lang">
          <option value="italy">意大利</option>
          <option value="english">英语</option>
          <option value="german">德语</option>
        </select>
      </div>

      <!-- 翻译框 -->
      <div class="box">
        <div class="input-wrap">
          <textarea v-model="obj.words"></textarea>
          <span><i>⌨️</i>文档翻译</span>
        </div>
        <div class="output-wrap">
          <div class="transbox">{{ result }}</div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
      // 需求:输入内容,修改语言,都实时翻译

      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
   
      const app = new Vue({
        el: '#app',
        data: {
          obj: {
            words: '旭哥',
            lang: 'italy'
          },
          result: '', // 翻译结果
        },
        watch: {
          obj: {
            deep: true, // 深度监视
            immediate: true, // 立刻执行,一进入页面handler就立刻执行一次
            handler (newValue) {  // handler 只要数据修改就触发
              clearTimeout(this.timer)
              this.timer = setTimeout(async () => {
                const res = await axios({
                  url: 'https://applet-base-api-t.itheima.net/api/translate',
                  params: newValue
                })
                this.result = res.data.data
                console.log(res.data.data)
              }, 300)
            }
          }


          // 'obj.words' (newValue) {
          //   clearTimeout(this.timer)
          //   this.timer = setTimeout(async () => {
          //     const res = await axios({
          //       url: 'https://applet-base-api-t.itheima.net/api/translate',
          //       params: {
          //         words: newValue
          //       }
          //     })
          //     this.result = res.data.data
          //     console.log(res.data.data)
          //   }, 300)
          // }
        }
      })
    </script>

注意深度监视 和普通监视的区别 还有handler的使用

综合案例

<div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt=""/></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">
        <span>🏠</span>
        /
        <span>购物车</span>
    </div>
    <!-- 购物车主体 -->
    <div class="main" v-if="fruitList.length > 0">
        <div class="table">
            <!-- 头部 -->
            <div class="thead">
                <div class="tr">
                    <div class="th">选中</div>
                    <div class="th th-pic">图片</div>
                    <div class="th">单价</div>
                    <div class="th num-th">个数</div>
                    <div class="th">小计</div>
                    <div class="th">操作</div>
                </div>
            </div>
            <!-- 身体 -->
            <div class="tbody">
                <div v-for="(item,index) in fruitList" :key="item.id" class="tr" :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">
                        <div class="my-input-number">
                            <button :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> -</button>
                            <span class="my-input__inner">{{item.num}}</span>
                            <button class="increase" @click="add(item.id)"> +</button>
                        </div>
                    </div>
                    <div class="td">{{item.num * item.price}}</div>
                    <div class="td">
                        <button @click="del(item.id)">删除</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">
            <!-- 全选 -->
            <label class="check-all">
                <input v-model="isAll" type="checkbox"/>
                全选
            </label>
            <div class="right-box">
                <!-- 所有商品总价 -->
                <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;<span
                        class="price">{{totalPrice}}</span></span>
                <!-- 结算按钮 -->
                <button class="pay">结算( {{totalCount}} )</button>
            </div>
        </div>
    </div>
    <!-- 空车 -->
    <div v-else class="empty">🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    const defaultArr = [
        {
            id: 1,
            icon: './img/火龙果.png',
            isChecked: true,
            num: 2,
            price: 6,
        },
        {
            id: 2,
            icon: './img/荔枝.png',
            isChecked: false,
            num: 7,
            price: 20,
        },
        {
            id: 3,
            icon: './img/榴莲.png',
            isChecked: false,
            num: 3,
            price: 40,
        },
        {
            id: 4,
            icon: './img/鸭梨.png',
            isChecked: true,
            num: 10,
            price: 3,
        },
        {
            id: 5,
            icon: './img/樱桃.png',
            isChecked: false,
            num: 20,
            price: 34,
        },
    ]
    const app = new Vue({
        el: '#app',
        data: {
            // 水果列表
            fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr
        },
        methods: {
            add(id) {
                const fruit = this.fruitList.find(item => item.id === id)
                fruit.num++
            },
            del(id) {
                this.fruitList = this.fruitList.filter(item => item.id !== id)
            },
            sub(id) {
                const fruit = this.fruitList.find(item => item.id === id)
                fruit.num--
            }
        },
        computed: {
            isAll: {
                get() {
                    // 如果所有的小选框都选中  则全选框也自动选中
                    return this.fruitList.every(item => item.isChecked)
                },
                set(value) {
                    // 基于拿到的布尔值,要让所有的小选框 同步状态
                    this.fruitList.forEach(item => item.isChecked = value)
                }
            },
            totalCount: {
                get() {
                    return this.fruitList.reduce((sum, item) => {
                        if (item.isChecked) {
                            return sum + item.num
                        } else {
                            return sum
                        }
                    }, 0)
                },
                set() {

                }
            },
            totalPrice: {
                get() {
                    return this.fruitList.reduce((sum, item) => {
                        if (item.isChecked) {
                            return sum + item.num * item.price
                        } else {
                            return sum
                        }
                    }, 0)
                },
                set() {

                }
            }
        },
        watch: {
            fruitList: {
                deep: true,     // 监听所有的内容
                handler(newValue) {
                    // 需要将变化后的 newValue 存入本地 (转JSON)
                    localStorage.setItem('list', JSON.stringify(newValue))
                }
            }
        }
    })
</script>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值