vue2/3学习(3)

237 阅读4分钟

watch 侦听器(监视器)

作用:监视数据变化,执行一些 业务逻辑 或 异步操作 屏幕截图 2024-01-23 174505.png

语法:

  1. 简单写法: 简单类型数据,直接监视
  2. 完整写法: 添加额外配置项

watch 简写

简单类型数据,直接监视

data:{
  word:'果果'
  obj:{
    word:'果果'
  }
},

watch:{
  // 该方法会在数据变化时,触发执行
  数据属性名(newValue,oldValue){
    一些业务逻辑 或 异步操作。
  },
  '对象.属性名'(newValue,oldValue){
    一些业务逻辑 或 异步操作。
  }
}

屏幕截图 2024-01-23 181249.png 一般情况下,老值都不会被用到,可以直接不写 屏幕截图 2024-01-23 181452.png

如果是监视对象里面的子属性,用 '对象.属性名'(newValue,oldValue){ } 屏幕截图 2024-01-23 181632.png

watch 完整写法

添加额外配置项,一次性对对象中的所有属性都做监视

  1. deep:true 对复杂类型深度监视
  2. immediate:true 初始化立即执行一次 handler 方法
data:{
  数据属性名:{
    words:'果果',
    lang:'Chinese'
  },
},

watch:{ // watch 完整写法
  数据属性名:{
    deep:true, //深度监视 
    // immediate:true 立刻执行,一进入页面 handler 就触发一次
    handler(newValue){ // handler 在数据修改时才触发
      console.log(newValue)
    }
  }
}

生命周期和生命周期的四个阶段

什么时候可以发送初始化渲染请求(越早越好)

什么时候可以开始操作 dom(至少 dom 渲染得出来,也就是至少是挂载阶段)

Vue 生命周期:一个 Vue 实例从创建销毁的过程
生命周期的四个阶段:创建、挂载、更新、销毁 屏幕截图 2024-01-23 202246.png

Vue 生命周期函数(钩子函数)

Vue 生命周期过程中,会自动执行一些函数,被称为 【生命周期钩子】 ——让开发者可以在【特定阶段】运行自己的代码屏幕截图 2024-01-23 203206.png

<script>
    const app = new Vue({
      el:'#app',
      data:{
        count:100,
        title:'计时器'
      },
      //1.创建阶段(准备数据)
      beforeCreate(){
        console.log('beforeCreate 响应式数据准备好之前',this.count)
      },
      created(){
        console.log('create 响应式数据准备好之后',this.count)
        // this.数据名 = 请求回来的数据
        // 可以开始发送初始化渲染的请求了
      },

      //2.挂载阶段(渲染模板)
      beforeMount(){
        console.log('beforeMount 模板渲染之前',document.querySelector('h3').innerHTML)
      },
      mounted(){
        console.log('mount 模板渲染之后',document.querySelector('h3').innerHTML)
        // 可以开始操作 dom 了
      },

      //3.更新阶段(修改数据,更新视图)
      beforeUpdata(){
        console.log('beforeUpdata 数据修改了,视图还没更新',document.querySelector('span').innerHTML)
      },
      updata(){
        console.log('updata 数据修改了,视图已经更新',document.querySelector('span').innerHTML)
      },

      //4.卸载阶段
      beforeDestroy(){
        console.log('beforeDestroy,卸载前')
        //清除掉一些 Vue 以外的资源占用:定时器、延时器...
      },
      destroy(){
        console.log('destroy,卸载后')
      }
    })
  </script>

生命周期的两个例子——初始化渲染&获取焦点

created 初始化渲染

屏幕截图 2024-01-23 211216.png

<script>
  const app = new Vue({
    el:'#app',
    data:{
      list:[]
    },
    async created () {
      // 1. 发送请求,获取数据
      const res = await axios.get('http://hmajax.itheima.net/api/news')
      // 2. 将数据更新给 data 中的 list
      this.list = res.data.data
    }
  })
</script>

mounted 获取焦点

一进入页面就自动获取焦点(其实就是修改 dom )

<div class="container" id="app">
  <div class="search-container">
    <img src="https://www.itheima.com/images/logo.png" alt="">
    <div class="search-box">
      <input type="text" v-model="words" id="inp">
      <button>搜索一下</button>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<script>
  const app = new Vue({
    el: '#app',
    data: {
      words: ''
    },
    // 核心思路:
    // 1. 等输入框渲染出来 mounted
    // 2. 让输入框获取焦点 inp.focus()
    mounted () {
      document.querySelector('#inp').focus()
    }
  })
</script>

案例——小黑记账本

屏幕截图 2024-01-23 212850.png

功能需求:

1. 基本渲染

  • 一进页面立刻发送请求获取数据
  • 拿到数据,存到 data 的响应式数据中
  • 结合数据,进行页面渲染 v-for
  • 消费统计 --> 用计算属性

2. 添加功能

  • 收集表单数据用v-model
  • 给添加按钮注册表单事件,发送添加请求
  • 需要重新渲染

3. 删除功能

  • 注册点击事件,并且由于需要知道要删除的是哪一个,所以要传参,也就是id
  • 根据id发送删除的请求

4. 饼图渲染

  • 初始化一个饼图:echarts,需要等dom渲染完,也就是需要mounted钩子实现
  • 根据数据实时更新饼图
 <div id="app">
      <div class="contain">
        <!-- 左侧列表 -->
        <div class="list-box">

          <!-- 添加资产 -->
          <form class="my-form">
            <input type="text" v-model.trim="name" class="form-control" placeholder="消费名称" />
            <input type="text" v-model.number="price" class="form-control" placeholder="消费价格" />
            <button type="button" class="btn btn-primary" @click="add">添加账单</button>
          </form>

          <table class="table table-hover">
            <thead>
              <tr>
                <th>编号</th>
                <th>消费名称</th>
                <th>消费价格</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(item,index) in list" :key="item.id">
                <td>{{index+1}}</td>
                <td>{{item.name}}</td>
                <td :class="{red:item.price>500}">{{item.price}}</td>
                <td><a @click="del(item.id)" href="javascript:;">删除</a></td>
              </tr>
            </tbody>
            <tfoot>
              <tr>
                <td colspan="4">消费总计: {{totalPrice.toFixed(2)}}</td>
              </tr>
            </tfoot>
          </table>
        </div>
        
        <!-- 右侧图表 -->
        <div class="echarts-box" id="main"></div>
      </div>
    </div>
    <script src="../echarts.min.js"></script>
    <script src="../vue.js"></script>
    <script src="../axios.js"></script>
    <script>
      
       
      
      const app = new Vue({
        el: '#app',
        data: {
          list:[],
          name:'',
          price:''
        },
        created(){
          //发送渲染的请求
          //这部分注释掉,因为要多次渲染发请求,所以我们再方法里封装一个方法
          // const res = await axios.get('https://applet-base-api-t.itheima.net/bill',{
          //   params:{
          //     creator:'小黑'
          //   }
          // })
          // this.list=res.data.data
          this.getList()
        },
        mounted () {
          this.myChart = echarts.init(document.querySelector('#main'))
          this.myChart.setOption({
            // 大标题
            title: {
              text: '消费账单列表',
              left: 'center'
            },
            // 提示框
            tooltip: {
              trigger: 'item'
            },
            // 图例
            legend: {
              orient: 'vertical',
              left: 'left'
            },
            // 数据项
            series: [
              {
                name: '消费账单',
                type: 'pie',
                radius: '50%', // 半径
                data: [
                  // { value: 1048, name: '球鞋' },
                  // { value: 735, name: '防晒霜' }
                ],
                emphasis: {
                  itemStyle: {
                    shadowBlur: 10,
                    shadowOffsetX: 0,
                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                  }
                }
              }
            ]
          })
        },
        computed:{
          totalPrice(){
            return this.list.reduce((sum,item)=>sum+item.price,0)
          }
        },
        methods:{
          //发送添加的请求
          async getList(){
            const res = await axios.get('https://applet-base-api-t.itheima.net/bill',{
            params:{
              creator:'小黑'
            }
          })
          this.list=res.data.data

          //在这里实现实时更新图表
          this.myChart.setOption({

             // 数据项
             series: [
              {//之前上面数据项传过的都不需要再传了,所以这里只写data就可以
                //data: [
                  // { value: 1048, name: '球鞋' },
                  // { value: 735, name: '防晒霜' }
                //],   
                data: this.list.map(item => ({value:item.price , name:item.name}))
              }
            ]

          })
          },
          async add(){
            if(!this.name){
              alert("请输入消费名称")
              return
            }
            if(typeof this.price !=='number'){
              alert("请输入正确价格")
            }
            //现在发请求
            const res=await axios.post('https://applet-base-api-t.itheima.net/bill',{
              creator:'小黑',
              name:this.name,
              price:this.price
            })
            //重新渲染,直接调用
            this.getList() 

            this.name=''
            this.price=''
          },
          async del (id) {
            // 根据 id 发送删除请求
            const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)
            // 重新渲染
            this.getList()
          }
        }
      })
    </script>