Vue2中的Tabs案例

365 阅读2分钟

Vue2中Tabbar案例

1.搭建项目目录

  • mytabs.vue:页面组件
  • myheader.vue:头部组件
  • mynavbar.vue:底部导航栏
  • mygoods.vue:商品列表
  • mysearch.vue:搜索
  • myinfo.vue:我的信息
  • mytable.vue:表格封装

2.myheader.vue组件的封装

<template>
  <div class="Myheader" :style="{ backgroundColor: background, color }">{{ title }}</div>
</template><script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    background: {
      type: String,
      default: '#ccc'
    },
    color: {
      type: String,
      default: '#fff'
    }
  }
}
</script><style lang="less" scoped>
.Myheader {
  height: 45px;
  background-color: rgb(0, 140, 255);
  text-align: center;
  line-height: 45px;
  color: #fff;
}
</style>

3.底部导航栏动态渲染

<template>
  <div class="tabscontainer">
    <div class="tabitem"
         v-for='(value,index) in list'
         :key='value.text'>
      <span :class="['iconfont',value.icon]"></span>
      <span>{{value.text}}</span>
    </div>
  </div>
</template><script>
export default {
  props: {
    list: {
      type: Array,
      required: true,
      validator (value) {
        if (value.length < 2 || value.length > 5) {
          return false
        } else {
          return true
        }
      }
    }
  }
}
</script>

4.数据模拟

 data() {
    return {
      comName: 'MyGoods',
      navs: [
        { id: 1, icon: 'icon-a-topliontubiaoku_gengduoguanli', text: '商品列表', comname: 'MyGoods' },
        { id: 2, icon: ' icon-a-topliontubiaoku_sousuo', text: '商品搜索', comname: 'MySearch' },
        { id: 3, icon: 'icon-a-topliontubiaoku_denglutouxiang', text: '我的信息', comname: 'MyInfo' }
      ]
    }
  },

5.使用父传子传递数据

<!-- 底部栏 -->
<mynavbar :list='tablist'></mynavbar>

6.导航栏功能的实现

<template>
  <div>
    <!-- 头部区域 -->
    <Myheader title="我的Tabs" background="skyblue" color="white"></Myheader>
    <!-- 动态组件区域 -->
    <component :is="comName"></component>
    <!-- 底部区域 -->
    <MyNavbar @exchange="exchange" :options="navs"></MyNavbar>
  </div>
</template><script>
import Myheader from './Myheader.vue'
import MyNavbar from './Mynavbar.vue'
import MyGoods from './MyGoods.vue'
import MySearch from './MySearch.vue'
import MyInfo from './MyInfo.vue'
export default {
  components: {
    Myheader,
    MyNavbar,
    MyGoods,
    MySearch,
    MyInfo
  },
  data() {
    return {
      comName: 'MyGoods',
      navs: [
        { id: 1, icon: 'icon-a-topliontubiaoku_gengduoguanli', text: '商品列表', comname: 'MyGoods' },
        { id: 2, icon: ' icon-a-topliontubiaoku_sousuo', text: '商品搜索', comname: 'MySearch' },
        { id: 3, icon: 'icon-a-topliontubiaoku_denglutouxiang', text: '我的信息', comname: 'MyInfo' }
      ]
    }
  },
  methods: {
    exchange(name) {
      this.comName = name
    }
  }
}
</script><style lang="less" scoped>
@import url('//at.alicdn.com/t/font_3259223_o7dt2dtyk6p.css');
</style>

7.ajax的封装

1.在src文件夹下新建一个utils文件夹,在utils文件夹中新建一个request.js文件并在其实配置基准路径

import axios from 'axios'
axios.defaults.baseURL = 'https://applet-base-api-t.itheima.net/'
export default axios

2.在src文件夹下新建一个apis文件夹,在apis文件夹下新建一个getGoods.js文件在该文件中配置方法

import axios from '@/utils/request'
export function getGoodList() {
  return axios({
    url: '/api/goods'
  })
}

3.在MyGoods.vue文件夹中发起ajax请求并将数据传递给MyTable.vue组件

 created() {
    getGoodList().then(res => {
      if (res.status == 200) {
        this.list = res.data.data
      }
    })
  },
  data() {
    return {
      list: []
    }
  },
 //在MyTable.vue组件中
props: {
    Goodslist: {
      type: Array,
      required: true
    }
  }
// 在MyGoods.vue组件中
<Mytable :Goodslist="list"></Mytable>

8.实现商品列表的渲染

1.标题可以使用具名插槽,让使用者决定到底渲染哪些数据

// 在MyTable.vue中定义具名插槽
<thead>
  <tr>
    <slot name="thead"></slot>
  </tr>
</thead>

2.在MyGoods组件中封装结构并写入具名插槽中

 <template #thead>
        <th scope="col">#</th>
        <th scope="col">商品名称</th>
        <th scope="col">商品价格</th>
        <th scope="col">标签</th>
        <th scope="col">操作</th>
      </template>

3.数据渲染可以使用 作用域插槽 让使用者决定数据的渲染格式

<tbody>
  <tr v-for="(item, index) in Goodslist">
    <slot name="tbody" :row="item" :index="index"></slot>
  </tr>
</tbody>

4.在MyGoods组件中拿到作用域插槽传递过来的数据并实现渲染

  <template #tbody="{ row, index }">
        <td>{{ index + 1 }}</td>
        <td>{{ row.goods_name }}</td>
        <td>¥{{ row.goods_price }}</td>
        <td>
        <td>{{row.tags}}</td>
      </template>

9.实现Tags的渲染

1.要封装的结构有:按钮,输入框,tags标签

<td>
  <input
         type="text"
         style="width: 100px"
         />
  <button class="btn btn-primary btn-sm">+tags</button>
  <span class="badge badge-warning" v-for="(item, index) in row.tags" :key="index">{{ item }}</span>
</td>
<td><button class="btn btn-danger btn-sm">删除</button></td>

10.实现Tags的操作

1.单击+tags,显示输入框,同时隐藏当前按钮(v-if)

<input
       type="text"
       style="width: 100px"
       v-if="row.inputVisible"
       />
<button class="btn btn-primary btn-sm" @click="row.inputVisible = true" v-else>+tags</

2.让输入框聚焦

// 在main.js中定义全局自定义指令
Vue.directive('focus', {
  inserted(el) {
    el.focus()
  }
})
// 在input标签中直接使用自定义指令实现聚焦
<input
       type="text"
       style="width: 100px"
       v-if="row.inputVisible"
       v-focus
       />
<button class="btn btn-primary btn-sm" @click="row.inputVisible = true" v-else>+tags</

3.为输入框添加失焦事件,隐藏输入框,显示按钮

<input
       type="text"
       style="width: 100px"
       v-if="row.inputVisible"
       v-focus
        @blur="row.inputVisible = false"
       />

4.按下enter键实现tag的添加

说明:

1.添加事件绑定,传入当前行数据对象-row

       ```vue

<input type="text" style="width: 100px" v-if="row.inputVisible" @blur="row.inputVisible = false" v-focus @keyup.enter="addTag(row)" /> ```

2.添加双向绑定,获取输入框的内容

<input
       type="text"
       style="width: 100px"
       v-if="row.inputVisible"
       @blur="row.inputVisible = false"
       v-focus
       v-model="row.inputValue"
       @keyup.enter="addTag(row)"
       />

3.将内容添加到数组

 addTag(obj) {
        obj.tags.push(obj.inputValue)
      }
    }

4.修改是否隐藏的状态值

addTag(obj) {
obj.tags.push(obj.inputValue)
obj.inputVisible = false
}
}

5.非空判断

 if (obj.inputValue.trim().length == 0) {
        alert('输入的标签不能为空')
        return
      }

6.有必要判断当前添加的tag是否重复,如果重复则不添加

 if (obj.tags.indexOf(obj.inputValue) == -1) {
        obj.tags.push(obj.inputValue)
        obj.inputValue = ''
        obj.inputVisible = false
      }

7.操作汇总

addTag(obj) {
      // 非空判断
      if (obj.inputValue.trim().length == 0) {
        alert('输入的标签不能为空')
        return
      }
      if (obj.tags.indexOf(obj.inputValue) == -1) {
        obj.tags.push(obj.inputValue)
        obj.inputValue = ''
        obj.inputVisible = false
      }
    }

8.按下esc键实现输入框清空

@keyup.esc="row.inputValue = ''"

11.实现点击删除按钮实现删除

// 绑定事件
<td><button class="btn btn-danger btn-sm" @click="del(row.id)">删除</button></td>
// 实现删除功能
del(id) {
this.list = this.list.filter(v => v.id != id)
},

12.总结

1️⃣父传子(props的应用)

2️⃣在线使用字体图标

3️⃣动态组件component配合is属性的使用

4️⃣子传父($emit)

5️⃣动态绑定样式

6️⃣ajax的封装

7️⃣具名插槽以及作用域插槽的使用

8️⃣自定义指令的使用

9️⃣数组方法的熟练运用

🔟Vue指令的熟练使用