前端:Vue学习-3

前端:Vue学习-3

    • [1. 自定义指令](#1. 自定义指令)
    • [2. 插槽](#2. 插槽)
      • [2.1 插槽 - 后备内容(默认值)](#2.1 插槽 - 后备内容(默认值))
      • [2.2 插槽 - 具名插槽](#2.2 插槽 - 具名插槽)
      • [2.3 插槽 - 作用域插槽](#2.3 插槽 - 作用域插槽)
    • [3. Vue - 路由](#3. Vue - 路由)
      • [3.1 路由模块封装](#3.1 路由模块封装)
      • [3.2 声明式导航 router-link 高亮](#3.2 声明式导航 router-link 高亮)
      • [3.3 自定义匹配的类名](#3.3 自定义匹配的类名)
      • [3.4 声明式导肮 - 跳转传参](#3.4 声明式导肮 - 跳转传参)
      • [3.5 Vue路由 - 重定向](#3.5 Vue路由 - 重定向)
      • [3.6 Vue路由 - 404](#3.6 Vue路由 - 404)
      • [3.7 Vue路由 - 模式设置](#3.7 Vue路由 - 模式设置)
      • [3.8 编程式导航 - 基本跳转,传参](#3.8 编程式导航 - 基本跳转,传参)

1. 自定义指令

自己定义的指令,可以封装一些dom操作,扩展额外功能。

全局注册,在main.js添加如下代码,以下代码为输入框自动聚焦。

js 复制代码
// focus为指令名
Vue.directive('focus',{
  inserted(el){
    el.focus();
  }
})
html 复制代码
<input type="text" v-focus>

运行结果:

局部注册,在组件内进行注册,只能在当前组件内使用该指令、

js 复制代码
directives:{
    focus:{
      inserted(el){
        el.focus();
      }
    }
  }

inserted提供的是元素被添加到页面时的逻辑,update 指令的值被修改时触发,提供值变化后,dom更新的逻辑。上述指令并没有给值,下述代码为给指令添加值。

html 复制代码
<template>
  <div id="app">
    <p v-color='color1'>北京</p>
    <p v-color='color2'>上海</p>
  </div>
</template>
<script>

export default {
  name: 'App',
  data(){
    return{
      color1:'red',
      color2:'blue'
    }
  },
  directives:{
    color:{
      inserted(el,binding){
        el.style.color = binding.value;
      },
      update(el,binding){
        el.style.color = binding.value;
      }
    }
  }
}
</script>
<style scoped>
  #app{
    width: 100px;
    height: 100px;
    margin: 20px auto;
  }
</style>

运行结果:

v-指令名="指令值",通过等号绑定指令的值;通过binding.value拿到指令的值

封装v-loading指令

本质loading效果就是一个蒙层,盖在盒子上;数据请求中,开启loading状态,添加蒙层;数据请求完毕,关闭loading状态,移除蒙层。

html 复制代码
<template>
  <div id="app">
      <div v-loading="loading"></div>
      <div>哈哈</div>
  </div>
</template>
<script>

export default {
  name: 'App',
  data(){
    return{
      loading:true
    }
  },
  directives:{
    loading:{
      inserted(el,binding){
        binding.value ? el.classList.add('loading'):el.classList.remove('loading');
      },
      update(el,binding){
        binding.value ? el.classList.add('loading'):el.classList.remove('loading');
      }
    }
  },
  created(){
    setTimeout(()=>{
      this.loading = false;
    },3000);
    // 等待3秒,只是演示效果
  }
}
</script>
<style scoped>
  #app{
    width: 500px;
    height: 500px;
    margin: 20px auto;
    position: relative;
  }
  .loading:before{
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgb(242,94,94) url('./static/1.gif') no-repeat center;
  }
</style>

运行效果:

2. 插槽

作用:让组件内部的一些结构支持自定义,可以定制结构或内容。

在组件内需要定制的结构部分,改动<slot></slot> 占位;使用组件时,在组件内部传入结构替换slot。

注意:只有两种插槽,默认插槽和具名插槽;

MyBase组件:

html 复制代码
<template>
	<div>
		<slot></slot>
	</div>
</template>

使用

html 复制代码
<MyBase>你好</MyBase>
<MyBase>你好2</MyBase>

这样的效果就是和下述代码一样

html 复制代码
<div>
	你好
</div>
<div>
	你好2
</div>

2.1 插槽 - 后备内容(默认值)

封装组件时,可以为预留的'<slot>'插槽提供默认值;直接在==<slot></slot>标签内,放置内容,作为默认显示内容==

子组件:

html 复制代码
<template>
    <div>
        <slot>你好</slot>
    </div>
</template>

<script>
export default {
    name:'MyBaseSlot'
}
</script>

<style>

</style>

父组件:

html 复制代码
<template>
  <div id="app">
    <MyBaseSlot></MyBaseSlot>    
    <MyBaseSlot>你好2</MyBaseSlot>   
  </div>
</template>
<script>
import MyBaseSlot from './components/MyBaseSlot.vue'

export default {
  name: 'App',
  data(){
    return{
      loading:true
    }
  },
  components:{
    MyBaseSlot
  }
}
</script>
<style scoped>
  #app{
    width: 500px;
    height: 500px;
    margin: 20px auto;
  }
  
</style>

运行结果:

2.2 插槽 - 具名插槽

一个组件内有多处结构,需要外部传入标签,进行定制。

使用,在组件内多个slot使用name属性区分名字,在调用该组件时,在该组件内使用template配合v-slot:属性名来分发对应标签,可以简化为#属性名;

子组件:MyBaseSlot

html 复制代码
<template>
    <div>
        <slot name="head">标题</slot>
        <p>什么都不是</p>
        <slot name="content">hello world!</slot>
    </div>
</template>

<script>
export default {
    name:'MyBaseSlot'
}
</script>

<style>

</style>

父组件:

html 复制代码
<template>
  <div id="app">
    <MyBaseSlot>
      <template v-slot:head>
        <div class="title">
          我是大标题
        </div>
      </template>
      <template #content>
        <div class="content">
          <p>我是内容</p>
          <img src="./static/1.jpg" alt="">
        </div>
      </template>
    </MyBaseSlot>
  </div>
</template>
<script>
import MyBaseSlot from './components/MyBaseSlot.vue'

export default {
  name: 'App',
  data(){
    return{
      loading:true
    }
  },
  components:{
    MyBaseSlot
  }
}
</script>
<style scoped>
  #app{
    width: 500px;
    height: 500px;
    margin: 20px auto;
    border: 1px solid black;
  }
  .title{
    width: 100px;
    height: 40px;
    line-height: 40px;
    background-color: red;
  }
  .content{
    width: 200px;
    height: 240px;
  }
  .content img{
    width: 200px;
  }
</style>

运行结果:

2.3 插槽 - 作用域插槽

定义slot插槽时,是可以进行传值的。插槽上可以绑定数据,将来使用组件时可以用。

  1. 给slot标签,以添加属性的方式传值;
  2. 所有添加的属性,都会被收集到一个对象中;
  3. 在template中,通过 '#插槽名="obj"'接收,默认插槽名为default
html 复制代码
<template>
    <div>
       <table style="margin-left:10px;margin-top:10px">
        <tr>
            <th>id</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>操作</th>
        </tr>
        <tr v-for="item in lists" :key="item.id">
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.age}}</td>
            <td>
                <slot :id="item.id" name="btn"></slot>
            </td>
        </tr>
       </table>
    </div>
</template>

<script>
export default {
    name:'MyBaseSlot',
    props:{
        lists:Array
    }
}
</script>

<style>
    tr{
        height: 40px;
    }
    td{
        width: 40px;
        text-align: center;
        line-height: 40px;
    }
    table{
        border: 1px solid black;
    }
</style>
html 复制代码
<template>
  <div id="app">
      <MyBaseSlot :lists="list1">
        <template #btn="obj">
          <button @click="fn(obj.id)">删除</button>
        </template>
      </MyBaseSlot>
  </div>
</template>
<script>
import MyBaseSlot from './components/MyBaseSlot.vue'

export default {
  name: 'App',
  data(){
    return{
        list1:[
          {id:1,name:'zs',age:12},
          {id:2,name:'ls',age:22},
          {id:3,name:'ww',age:32},
          {id:4,name:'zl',age:19}
        ]
    }
  },
  components:{
    MyBaseSlot
  },
  methods:{
    fn(id){
      this.list1 = this.list1.filter((item)=>item.id != id)
    }
  }
}
</script>
<style scoped>
  #app{
    width: 500px;
    height: 500px;
    margin: 20px auto;
    border: 1px solid black;
  }
  .title{
    width: 100px;
    height: 40px;
    line-height: 40px;
    background-color: red;
  }
</style>

运行结果:

3. Vue - 路由

路径和组件的映射关系。

安装VueRouter

js 复制代码
npm install vue-router@3.6.5
js 复制代码
import VueRouter from 'vue-router'
// 引入
Vue.use(VueRouter)
// 安装注册
const router = new VueRouter();
// 创建路由对象
注入路由对象到Vue实例中
new Vue({
	render:h=>h(App),
	router
}).$mount('#app')

此时的访问路径出现了"#/"

创建views目录,用来存储组件,配置路由规则。

js 复制代码
const router = new VueRouter({
	routes:[
		{path:'/find',component:Find}
	]
})

配置导航,配置路由出口(路径匹配的组件显示的位置)

html 复制代码
<a href='#/find'>发现</a>
<router-link to="/find">发现</router-link>
<router-view></router-view>
js 复制代码
const router = new VueRouter({
  routes: [
    { path: '/find', component: Find },
    { path: '/myMusic', component: My },
    { path: '/friend', component: Friend }
  ]
});
html 复制代码
<template>
  <div id="app">
      <a href="#/find">发现音乐</a>
      <router-link to="/myMusic">我的音乐</router-link>
      <router-link to="/friend">我的朋友</router-link>
      <router-view></router-view>
  </div>
</template>

运行结果:

组件存放目录问题,页面组件 放在views目录下,复用组件放在components目录下。

3.1 路由模块封装

把路由相关代码用单独js文件来实现,提高代码的可读性和可维护性。

index.js

js 复制代码
import Vue from 'vue'
import VueRouter from 'vue-router'
import Find from '@/views/Find.vue'
import My from '@/views/My.vue'
import Friend from '@/views/Friend.vue'

Vue.use(VueRouter);

const router = new VueRouter({
    routes: [
        { path: '/find', component: Find },
        { path: '/myMusic', component: My },
        { path: '/friend', component: Friend }
    ]
});

export default router

main.js

js 复制代码
import router from './router/index'

router-link 本质上就是a标签,配置其to属性,表示路由路径。默认会提供高亮类名。

router-link会自动添加两个高亮类名,为router-link-active和router-link-exact-active,其中 router-link-active 模糊匹配,而router-link-exact-active 为精确匹配。

router-link-active 能够匹配 /find /find/one /find/two

router-link-exact-active 只能匹配 /find

3.3 自定义匹配的类名

router-link的两个高亮类名太长了,如何进行自定义呢?直接在VueRouter中进行配置即可。

js 复制代码
const router = new VueRouter({
    routes: [
        { path: '/find', component: Find },
        { path: '/myMusic', component: My },
        { path: '/friend', component: Friend }
    ],
    linkActiveClass:'active',
    linkExactActiveClass:'exact-active'
});

3.4 声明式导肮 - 跳转传参

查询参数传参
to="/path?参数名=值"

对应页面接收传递的参数值

js 复制代码
$route.query.参数名
html 复制代码
<template>
  <div>
    发现音乐
    <p>{{$route.query.title}}</p>
  </div>
</template>


动态路由传参

配置动态路由

js 复制代码
{ path: '/find/:参数名', component: Find },

{ path: '/find/:参数名?', component: Find },这种方式表示在不传参时也可以匹配到对应组件;如果用上述方式,当不传参时,则不会匹配到对应的组件。

导航链接为:

html 复制代码
<router-link to='/find/我的梦'></router-link>

对应页面租价接收传递过来的值

js 复制代码
$route.params.参数名

两种传参方式的区别:

查询参数传参,比较适合多个参数,获取方式通过 $route.query.参数名;动态路由传参,优雅简洁,传递单个参数比较方便,获取方式通过 $route.params.参数名

3.5 Vue路由 - 重定向

在VueRouter配置项添加redirect,如下

js 复制代码
const router = new VueRouter({
    routes: [
        { path: '/', redirect: '/find'},
        { path: '/find/:title?', component: Find },
        { path: '/myMusic', component: My },
        { path: '/friend', component: Friend }
    ],
    linkActiveClass:'active',
    linkExactActiveClass:'exact-active'
});

运行结果:

3.6 Vue路由 - 404

当路径找不到匹配时,给个提示页面;新建页面组件NotFound,然后在VueRouter配置项最后添加=={path:'*',component:NotFound}==,表示前面路径都没有匹配到时,跳转到这个NotFound页面。

js 复制代码
routes: [
        { path: '/', redirect: '/find'},
        { path: '/find/:title?', component: Find },
        { path: '/myMusic', component: My },
        { path: '/friend', component: Friend },
        { path: '*', component: NotFound}
    ]

运行结果:

3.7 Vue路由 - 模式设置

两种模式:

hash模式(默认),比如:http://localhost:8080/#/find

history路由,比如:http://localhost:8080/find

直接在VueRouter配置即可,配置如下:

js 复制代码
const router = new VueRouter({
	routes,
	mode:'history'
})

3.8 编程式导航 - 基本跳转,传参

1.path路径跳转

js 复制代码
this.$router.push('/find')
// 简写
this.$router.push({
	path:'/find'
})
// 完整写法

2.name命名路由跳转(适合path路径长的场景)

js 复制代码
this.$router.push({
	name:'路由名'
})

// 路由配置为:
{name:'路由名',path:'路径',component:xxx}

路由传参

两种传参方式:查询参数、动态路由传参
1.查询参数

js 复制代码
this.$router.push('/find?title=我的梦&page=1&size=10')
// 简写
this.$router.push({
	path:'/find',
	query:{
		title:'我的梦',
		page:1,
		size:10
	}
})
// 详细写法

2.动态路由传参

js 复制代码
this.$router.push('/find/我的梦')
//或
this.$router.push({
		path:'/find/我的梦'
})

上述两种方式参数接收方和声明式导航一样。
使用命名路由进行传参:
查询参数进行传参 query

js 复制代码
this.$router.push({
	name:'路由名',
	query:{
		'参数名':'值',
		...
	}
})

动态路由进行传参 params

js 复制代码
this.$router.push({
	name:'路由名',
	params:{
		'参数名':'值',
	}
})
相关推荐
风尚云网8 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子020411 分钟前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing13 分钟前
React核心功能详解(一)
前端·react.js·前端框架
捂月16 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆23 分钟前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China24 分钟前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q25 分钟前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海26 分钟前
Chrome离线安装包下载
前端·chrome
m512736 分钟前
LinuxC语言
java·服务器·前端
运维-大白同学1 小时前
将django+vue项目发布部署到服务器
服务器·vue.js·django