vue(5-6)

143 阅读3分钟

vue第五天

一、案例-购物车

1653185236741.png

1.获取数据

(1)在reques.js文件中设置引入axios,并设置基地址

// utils/request.js
// 改造 axios 添加基地址后重新导出
import axios from 'axios'
axios.defaults.baseURL = 'https://www.escook.cn'

export default axios

(2)在api文件夹中创建cart.js文件,并且引入经过修改request.js,封装接口函数,导出供页面使用,获取购物车数据(具名导出,与其他函数进行区分)

import request from "@/utils/request.js"
export function getCar(){
    return request({
        url:"/api/cart"
    })
}

(3)在App.vue父组件中,引入子组件CartHeader.vue和ProdItem.vue,并在页面进入时发送请求

<script>
  import CartHeader from "@/components/CartHeader.vue"
  import ProdItem from "@/components/ProdItem.vue"
  import {getCart} from "@/api/cart.js"
    
  export default {
      components:{
          ProdItem,
          CarHeader,
      },
      created(){
          getCart().then(res=>{
              console.log("页面进入数据获取完毕")
              console.log(res.data)
          })
      }
  }
</script>
2.渲染商品

父组件App.vue

<template>
  <div>
    <CartHeader bg="#1d7bff" title="我的购物车"/>
    <div class="list">
      <ProdItem v-for="item in list" :key="item.id" :data="item"/>
    </div>
    <div class="footer">
      <input type="checkbox" name="" id="">
      <div class="total">合计¥1151.8</div>
      <button>结算</button>
    </div>
  </div>
</template>

子组件ProdItem.vue

<template>
  <div class="item">
    <input v-model="data.goods_state" class="checkbox" type="checkbox" name="" :id="data.id"/>
      
    <!-- label ,for data.id绑定可提高用户体验:点击到img时,复选框选中或取消 -->
    <label :for="data.id">
      <img :src="data.goods_img" alt="" />
    </label>
    <div class="info">
      <div class="top">{{ data.goods_name }}</div>
      <div class="bottom">
        <div class="price">¥ {{ data.goods_price }}</div>
        <div class="number">
          <button @click="data.goods_count--">-</button>
          <input type="number" v-model.number="data.goods_count" />
          <button @click="data.goods_count++">+</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: ["data"],
};
</script>
3.单一商品选中

主要是复习了 label 标签的使用

<!-- label ,for data.id绑定可提高用户体验:点击到img时,复选框选中或取消 -->
<input v-model="data.goods_state" class="checkbox" type="checkbox" name="" :id="data.id" />
<label :for="data.id">
  <img :src="data.goods_img"/>
</label>
4.单一商品数量

输入框已经绑定好,需要做修改的是加减按钮

<div class="number">
   <button @click="data.goods_count--">-</button>
   <input type="number" v-model.number="data.goods_count" />
   <button @click="data.goods_count++">+</button>
</div>
export default {
  watch: {
    "data.goods_count": function (newVal) {
      if (newVal < 1) {
        this.data.goods_count = 1;
      }
    },
  },
};
5.全选按钮

(1)被动 carfooter.vue

export default {
  props: ['list'],
  computed: {
    isAll() {
      return this.list.every(item=>item.goods_state)
    }
  }
};

(2)主动carfooter.vue

export default {
    props: ['list'],
    computed: {
      isAll: {
        get() {
          return this.list.every(item=>item.goods_state)
        },
        set(isChecked) {
          // 这里可以接收到全选的布尔值, 
          // 将所有商品状态改为跟全选状态一样即可
          this.list.forEach(element => {
            element.goods_state = isChecked
          });
        }
      }
    }
  };
6.总数量和总价格
totalPrice() {
  // 总价=列表中所有被勾选的商品的单价乘以数量累加起来
  let res = 0
  this.list.forEach(element => {
    if (element.goods_state) {
      res += element.goods_count * element.goods_price
    }
  });
  return res
},
totalCount() {
  let res = 0
  this.list.forEach(element => {
    if (element.goods_state) {
      res += element.goods_count
    }
  });
  return res
}

二、动态组件、组件缓存、声明周期扩展

1.动态组件

(1)作用:

多个组件使用同一个挂载点,并动态切换

(2)分析

①准备被切换的 - UserName.vue / UserInfo.vue 2个组件

②引入到App.vue注册

③准备变量来承载要显示的"组件名"

④设置挂载点, 使用is属性来设置要显示哪个组件

⑤点击按钮 – 修改comName变量里的"组件名"

<template>
  <div>
    <button @click="componentName = 'UserInfo'">个人信息</button>
    <button @click="componentName = 'UserName'">账号登录</button>
    <!-- vue内置标签 component 是动态组件挂载点, 会根据绑定的 is 属性显示名字对应的组件 -->
    <component :is="componentName" />
  </div>
</template>

<script>
import UserInfo from '@/components/UserInfo.vue'
import UserName from '@/components/UserName.vue'
export default {
  data() {
    return { 
      componentName: 'UserInfo'
    }
  },
  components: {
    UserInfo,
    UserName
  }
}
</script>

<style></style>
2.缓存组件-初步使用

keep-alive标签包裹动态组件挂载点

<keep-alive>
  <component :is="componentName" />
</keep-alive>
3.生命周期拓展

activated – 激活时触发 deactivated – 失去激活状态触发

activated() {
  console.log('缓存的组件被激活(显示)');
},
deactivated() {
  console.log('缓存的组件被隐藏');
}

三、插槽使用

1.作用:

通过 slot 标签, 让组件内可以接收不同的标签结构显示

2.语法:

(1)组件内用占位

(2)使用组件时夹着的地方, 传入标签替换slot

父组件:App.vue

<template>
  <div>
    <!-- 员工页使用, 就要带导入员工新建员工按钮 -->
    <TopBar>
      <button>新增员工</button>
      <button>导入员工</button>
    </TopBar>
    <!-- 工资页面使用需要一个报表按钮 -->
    <TopBar>
      <button>报表</button>
    </TopBar>
  </div>
</template>

<script>
import TopBar from '@/components/TopBar.vue'
export default {
  components: {
    TopBar
  }
}
</script>

<style>

</style>

子组件:子组件.vue

<template>
  <div class="topBar">
    <div class="left"></div>
    <div class="right">
      <!-- 插槽占位标签 -->
      <slot/>
    </div>
  </div>
</template>

<script>
export default {

}
</script>

<style lang="less" scoped>
.topBar {
  display: flex;
  justify-content: space-between;
  border: 2px solid salmon;
}
</style>
3.默认显示内容设定
<template>
  <div class="topBar">
    <div class="left"></div>
    <div class="right">
      <!-- 插槽占位标签 -->
      <slot>
        <!-- 如果外面没有传入, 默认显示的内容 -->
        欢迎来到我的页面
      </slot>
    </div>
  </div>
</template>
4.具名插槽

(1)作用:

一个组件内有2处以上需要外部传入标签的地方

(2)语法:

①slot使用name属性区分名字

<div class="left">
  <slot name="left"/>
</div>
<div class="right">
  <!-- 插槽占位标签 -->
  <slot name="right">
    <!-- 如果外面没有传入, 默认显示的内容 -->
    欢迎来到我的页面
  </slot>
</div>

②template配合v-slot:名字来分发对应标签

    <TopBar>
      <!-- v-slot: 可以被简化成# -->
      <template #left>
        一共 666 位员工
      </template>
      <template #right>
        <button>新增员工</button>
        <button>导入员工</button>
      </template>
    </TopBar>
    <!-- 工资页面使用需要一个报表按钮 -->
    <TopBar>
      <template v-slot:left>
        5月工资报表
      </template>
      <template v-slot:right>
        <button>报表</button>
      </template>
    </TopBar>
5.作用域插槽

(1)作用:

使用插槽时, 想使用子组件内变量

(2)语法:

①子组件, 在slot上绑定属性和子组件内的值

②使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"

③scope变量名自动绑定slot上所有属性和值 scope = {row: defaultObj}

子组件:

<slot :row="monthList" name="left">
  {{monthList.first}} 工资报表
</slot>

父组件:

<template v-slot:left="scope">
  {{scope.row.second}} 工资报表
</template>
6.作用域插槽具体使用场景

封装一个灵活的表格组件

<template>
  <div>
    <slotVue>
      <template v-slot:left="scope">
        <div>{{ scope.row.second }}月工资表</div>
      </template>
      <!-- v-slot:名 简写 #名  #right -->
      <template v-slot:right>
        <button>新增</button>
        <button>报表</button>
      </template>
    </slotVue>
  </div>
</template>

<script>
import slotVue from "./components/slot.vue";
export default {
  components: {
    slotVue,
  },
};
</script>

7.自定义指令的使用方式
<template>
  <div>
    <!-- 使用自定义指令, 跟普通vue指令一样, 请千万注意,要加上 v- 前缀 -->
    <input type="text">
    <br>
    <input type="text">
    <br>
    <input v-autofocus type="text">
  </div>
</template>

<script>
export default {
  // 局部指令注册
  // directives: {
    // 指令名字符串: {
        // 配置对象
        // 可以指定使用这个指令的元素, 在不同生命周期执行的函数
        // 在这些钩子函数的形参中, 默认第一个可以获取元素本身, 第二个可以用来传参
        // inserted,
        // update
    // }
  // }
  directives: {
    autofocus: {
      inserted(el) {
        console.log(el, '自动聚焦');
        el.focus()
      }
    }
  }
}
</script>

<style>

</style>