vue2笔记和TabBar笔记

122 阅读3分钟

自定义指令

目标:获取标签,扩展额外功能

1.全局注册

Vue.directive("指令名",{
    "inserted"(el){
        //可以对el标签扩展额外功能
    }
})

2.局部注册

directives:{
    "指令名":{
        inserted(el){
            //对el进行操作
        }
    }
}

3.使用自定义标签

在标签上使用自定义指令 v-指令名

注意

inserted方法 - 指令所在标签被插入到网页上时就出发

自定义指令传值

语法

例如定义color指令-传入一个颜色,给标签设置字体颜色

Vue.directive("color",{
    inserted(el,binding){ // 当贝绑定元素插入到父元素中时调用
        el.style.color = binding.value;
    },
    update(el,binding){ // 值或模板更新时,触发此函数
        el.style.color = binding.value; //传值的时候要传字符串 - v-color="'red'"
        // 或者可以在data里设置一个变量colorStr='red',然后v-color="colorStr"
    }
})

TabBar案例

1.练习了一下用组件标签实现组件切换 2.再次熟悉了用axios请求数据 3.熟悉了刚复习的插槽的使用 4.熟悉了自定义指令的用法,以及对一些Vue指令的用法更加熟练 5.各个组件用了bootstrap包装的样式

MyHeader组件

复用了之前购物车案例里的MyHead组件

MyTabBar组件

<template>
   <div class="my-tab-bar">
       <div class="tab-item"
       v-for="(item,index) in arr"
       :key="index"
       @click="btn(index,item)"
       :class="{current:index===setIndex}"
           >
       <!-- 图标 -->
       <span class="iconfont" :class="item.iconText"></span>
       <!-- 文字 -->
       <span> {{ item.text }} </span>
   </div>
   </div>
</template>

<script>
export default {
   props:{
       arr:{
           type:Array,
           require:true,
           //自定义校验规则
           validator(value){
               if(value.length>=2&&value.length<=5){
                   return true;
               }
               else{
                   console.error("数据员必须在2-5项");
                   return false;
               }
           }
       }
   },
   data() {
       return {
           setIndex: 0,
       };
   },
   methods:{
       btn(index,obj){
           this.setIndex=index;
           this.$emit('changeName',obj.componentName)
       }
   }
}
</script>

<style lang="less" scoped>
.my-tab-bar {
   position: fixed;
   left: 0;
   bottom: 0;
   width: 100%;
   height: 50px;
   border-top: 1px solid #ccc;
   display: flex;
   justify-content: space-around;
   align-items: center;
   background-color: white;
   .tab-item {
   display: flex;
   flex-direction: column;
   align-items: center;
   }
}
   
.current {
   color: #1d7bff;
}
</style>

MyTable组件

<template>
    <table class="table table-bordered table-stripped">
    <!-- 表格标题区域 -->
    <thead>
        <tr>
            <slot name="header">
                <th>#</th>
                <th>商品名称</th>
                <th>价格</th>
                <th>标签</th>
                <th>操作</th>
            </slot>
        </tr>
    </thead>
    <!-- 表格主体区域 -->
    <tbody>
        <tr v-for="item in arr" :key="item.id">
            <slot name="body" :row="item">
                <td> {{ item.id }} </td>
                <td>{{ item.goods_name }}</td>
                <td>{{ item.goods_price }}</td>
                <td>{{ item.tags }}</td>
                <td>
                    <button>删除</button>
                </td>
            </slot>
        </tr>
    </tbody>
    </table>
</template>

<script>
export default {
    name: 'MyTable',
    props:['arr'],
    methods:{
        
    }
}
</script>


<style scoped lang="less">
.my-goods-list {
    .badge {
    margin-right: 5px;
    }
}
</style>

MyGoodsList组件

<template>
    <div>
        <MyTable :arr="list">
            <template #header> 
                <th>#</th>
                <th>商品名称</th>
                <th>价格</th>
                <th>标签</th>
                <th>操作</th>
            </template>
            <template v-slot:body="scope">
                <td> {{ scope.row.id }} </td>
                <td>{{ scope.row.goods_name }}</td>
                <td>{{ scope.row.goods_price }}</td>
                <td>
                    <input type="text" 
                    class="tag-input form-control"
                    v-if="scope.row.inputVisible"
                    v-focus
                    @blur="scope.row.inputVisible = false"
                    @keydown.enter="enterFn(scope.row)"
                    v-model="scope.row.inputValue"
                    style="width:100px">
                    <button style="display:block" 
                    class="btn btn-primary btn-sm add-tag"
                    v-else
                    @click="scope.row.inputVisible = true"
                    >+Tag</button>
                    <span class="btn btn-primary" style="background:white;color:blue" v-for="(item,index) in scope.row.tags" :key="index">{{ item }}</span>
                </td>
                <td>
                    <button class="btn btn-danger btn-sm" @click="delFn(scope.row.id)">删除</button>
                </td>
            </template>
        </MyTable>
    </div>
</template>

<script>
    import axios from 'axios'
    import MyTable from '@/components/MyTable.vue';
    axios.defaults.baseURL = 'https://www.escook.cn'
export default {
    components:{
        MyTable
    },
    data() {
        return {
            list: [],
        };
    },
    created(){
        axios({
            url:'/api/goods'
        }).then((res)=>{
            console.log(res);
            this.list=res.data.data;
        })
    },
    methods:{
        delFn(id){
            let index = this.list.findIndex(item=>item.id==id);
            this.list.splice(index,1)
            // this.list = this.list.filter(item=>{
            //     item.id!=id
            // })
        },
        enterFn(item){
            if(item.inputValue.trim().length==0)return alert('请输入数据')
            item.tags.push(item.inputValue)
            item.inputValue=''
        }
    },
    
}
</script>

<style>
</style>

App.vue

<template>
  <div>
    <MyHeader background="blue" color="white" title="TabBar案例"></MyHeader>
    <div class="main">
      <component :is="comName"></component>
    </div>
    <MyTabBar :arr="tabList" @changeName="changeName"></MyTabBar>
  </div>
</template>

<script>
  import MyHeader from './components/MyHeader.vue';
  import MyTabBar from './components/MyTabBar.vue';
  import MyTable from './components/MyTable.vue';
  import MyGoodsList from './view/MyGoodsList.vue';
  import MyGoodsSearch from './view/MyGoodsSearch.vue';
  import MyUserInfo from './view/MyUserInfo.vue';
export default {
  data() {
    return {
      comName:'MyGoodsList',
      tabList: [
          {
              iconText: "icon-shangpinliebiao",
              text: "商品列表",
              componentName: "MyGoodsList"
          },
          {
              iconText: "icon-sousuo",
              text: "商品搜索",
              componentName: "MyGoodsSearch"
          },
          {
              iconText: "icon-user",
              text: "我的信息",
              componentName: "MyUserInfo"
          }
      ]
    };
  },
  components:{
    MyHeader,
    MyTabBar,
    MyTable,
    MyGoodsList,
    MyGoodsSearch,
    MyUserInfo,
  },
  methods:{
    changeName(cName){
      this.comName = cName
    }
  }
}
</script>

<style lang="less">
  *{
    margin: 0;
    padding: 0;
    list-style: none;
  }
</style>

main.js里引入bootsap.css和定义自定义指令focus

Vue-Router

vue-router模块

  • 步骤
    • 1.下载vue-router模块到当前工程
    • 2.在main.js里引入VueRouter函数
    • 3.添加到Vue.use()上-注册全局RouterLink和RouterView组件
    • 4.创建路由规则数组-路径和组件名对应关系
    • 5.用规则生成路由对象
    • 6.把路由对象注入到new Vue实例中
    • 7.用router-view作为挂载点,切换不同的路由页面

声明式导航

目标:可用组件router-link来代替a标签

1.vue-router提供了一个全局组件router-link 2.router-link实质上最终会渲染为a链接 to属性等价于提供 href属性(to无需#) 3.router-link提供了声明式导航高亮的功能(自带类名)

vue-router的基础使用

App.vue

<template>
  <div>
    <div class="footer_wrap">
      <router-link to="/find">发现音乐</router-link>
      <router-link to="/my">我的音乐</router-link>
      <router-link to="/part">朋友</router-link>
    </div>
    <div class="top">
      <!-- 设置挂载点-当url的hash值路径切换,显示规则里对应的组件到这 -->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {};
</script>

<style scoped>
  .footer_wrap {
    position: fixed;
    left: 0;
    top: 0;
    display: flex;
    width: 100%;
    text-align: center;
    background-color: #333;
    color: #ccc;
  }
  .footer_wrap a {
    flex: 1;
    text-decoration: none;
    padding: 20px 0;
    line-height: 20px;
    background-color: #333;
    color: #ccc;
    border: 1px solid black;
  }
  .footer_wrap a:hover {
    background-color: #555;
  }
  .top {
    padding-top: 62px;
  }
</style>

main.js

import Vue from 'vue'
import App from './App.vue'
import Find from '@/view/Find.vue'
import My from '@/view/My.vue'
import Part from '@/view/Part.vue'
import VueRouter from 'vue-router'




Vue.config.productionTip = false
Vue.use(VueRouter)

const routes = [
  {
    path:'/find',
    component:Find
  },
  {
    path:'/my',
    component:My
  },
  {
    path:'/part',
    component:Part
  },
  {
    path:'/part/:username'
  }
]

//生成路由对象
const router = new VueRouter({
  routes
})

new Vue({
  render: h => h(App),
  router
}).$mount('#app')

声明式导航-跳转传参

目标:再跳转路由时,可以给路由对应的组件内传值

方式1

  • 在router-link上的to属性传值,语法格式:
    • /path?参数名=值
  • 对应页面组件接收传递过来的值
    • $router.query.参数名

方式2

  • 在router-link上的to属性传值,语法格式:
    • /path/值
  • 对应的路由规则要有定义
    • 路由规则path上 定义 /path/:参数名
  • 接收:
    • $route.params.参数名
    <div>
        <p>我的朋友</p>
        <p>我的关注</p>
        <p>发现精彩</p>
        <p>人名:{{ $route.query.name }} -- {{ $route.params.username }}</p>
    </div>
  {
    path:'/part/:username',
    component:Part
  }
      <router-link to="/part?name=小船">朋友-小船</router-link>
      <router-link to="/part/小智">朋友-小智</router-link>

路由的重定向

目标:匹配path后,强制跳转path路径

  • 网页打开url默认hash值是/路径
  • redirect是设置要重定向到哪个路由路径
{
    path:'/', //默认hash值路径
    redirect:'/find' //重定向到/find
    // 浏览器url中#后的路径被改变成/find-重新匹配规则
}

路由404设置

目标:找不到路径给个提示页面

  • 路由最后,path匹配*(任意路径)- 前面不匹配就命中最后这个
const routes = [
  {
    path:'/find',
    component:Find
  },
  {
    path:'/my',
    component:My
  },
  {
    path:'/part',
    component:Part
  },
  {
    path:'/part/:username',
    component:Part
  },
  {
    //404在最后(规则是从前往后逐个比较path)
    path:'*',
    component:NotFound
  }
]

路由模式修改

目标:修改路由在地址栏的模式

const router = new VueRouter({
    routes,
    mode:"history"
})

编程式导航 - 基础使用

目标:用js代码来进行跳转

  • 语法:path或者name任意选一个
this.$router.push({
    path:'路由路径',// 都去 router/index.js定义
    name:'路由名'
})
<span @click="btn('/find','Find')">搜索</span>
<span @click="btn('/my','My')">我的收藏</span>
<span @click="btn('/part','Part')">我的朋友</span>
methods:{
    btn(targetPath,targetName){
        //方式1:path跳转
        this.$router.push({
            path:targetPath,
            name:targetName
        })
    }
}

注意:虽然用name跳转,但是url的hash值还是切换path路径

场景:

  • 方便修改:name路由名(在页面上看不见随便定义)
  • path可以再url的hash值看到(尽量符合组内规范)

编程式导航 - 跳转路由传参

  • params/query:
this.$router.push({
    params/query:{
        username:'小船'
    }
})

重要:path会自动忽略params

推荐:name+query方式传参

路由嵌套

目标:在现有的一级路由下,在潜逃二级路由

  • 1.创建需要用的所有组件
  • 2.main.js-继续配置2级路由
    • 一级路由path从/开始定义
    • 二级路由往后path直接写名字,无需/开头
    • 嵌套路由在上级路由的children数组里编写路由信息对象
  • 3.router-view
    • App.vue的router-view负责一级路由
    • 二级路由由一级路由里的router-view负责
{
    path:'/find',
    component:Find,
    children:[
      {
        path:'recommend',
        component:Recommend
      },
      {
        path:'music',
        component:Music
      },
      {
        path:'search',
        component:Search
      },
    ]
  },