自定义指令
目标:获取标签,扩展额外功能
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
}
]
路由模式修改
目标:修改路由在地址栏的模式
- hash路由例如:http://localhost:8080/#/home
- history路由例如:http://lacalhost:8080/home(以后上线需要服务器端支持)
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
},
]
},