Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)

本文主要是介绍Vue2到3 Day5 全套学习内容,众多案例上手(内付源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介:

Vue2到3 Day1-3 全套学习内容,众多案例上手(内付源码)_星辰大海1412的博客-CSDN博客本文是一篇入门级的Vue.js介绍文章,旨在帮助读者了解Vue.js框架的基本概念和核心功能。Vue.js是一款流行的JavaScript前端框架,被广泛用于构建现代、响应式的Web应用。通过深入浅出的方式,文章将介绍Vue.js的基本概念,如组件、指令、双向数据绑定等,并演示如何使用Vue.js开发一个简单的示例应用。无论您是初学者还是有经验的前端开发者,本文都将为您提供一个良好的起点,让您能够迅速上手并充分利用Vue.js的强大功能https://blog.csdn.net/m0_61662775/article/details/131949855?spm=1001.2014.3001.5501
Vue2到3 Day4 全套学习内容,众多案例上手(内付源码)_星辰大海1412的博客-CSDN博客通过这篇文章了解Vue的响应式数据机制,以及如何使用data属性来实现数据驱动的界面更新。学习如何使用计算属性、侦听器等处理数据逻辑。https://blog.csdn.net/m0_61662775/article/details/132221004?spm=1001.2014.3001.5501

接下里的学习内容如下: 

吾生也有涯,而知也无涯。学无止境,然犹需沉潜。兢兢业业,方能于浩瀚知识的汪洋中,稍觉安宁。加油!

 

目录

简介:

一、自定义指令

自定义指令-指令的值 

自定义指令 - v-loading 指令的封装

二、🌟①插槽-默认插槽

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

③插槽-具名插槽 

④作用域插槽

🌟综合案例 - 商品列表-MyTag组件抽离

1.需求说明

2.my-tag组件封装-创建组件

3.MyTag组件控制显示隐藏

4.MyTag组件进行 v-model 绑定

5.封装MyTable组件-动态渲染数据

6.综合案例-封装MyTable组件-自定义结构

三、单页应用程序介绍

1.路由介绍

2.路由的介绍

四、路由的基本使用

两个核心步骤

组件的存放目录问题

 


一、自定义指令

1.指令介绍:

  • 内置指令:v-html、v-if、v-bind、v-on... 这都是Vue内置的一些指令,可以直接使用

  • 自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令

    每个指令都有自己各自独立的功能

2.自定义指令:

概念:自己定义的指令,可以封装一些DOM操作,扩展额外的功能

📜示例:

需求: 当页面加载时,让元素将获得焦点

(autofocus 在 safari 浏览器有兼容性)

操作dom:  dom元素.focus()

mounted () {this.$refs.inp.focus()
}

3.自定义指令语法

1️⃣全局注册-语法:

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

 2️⃣局部注册-语法:

//在Vue组件的配置项中
directives: {"指令名": {inserted () {// 可以对 el 标签,扩展额外功能el.focus()}}
}
  • 使用指令

    ⭕注意:在使用指令的时候,一定要先注册再使用,否则会报错
    使用指令语法: v-指令名。如:

    <input v-指令名 type="text">

    注册指令时不用v-前缀,但使用时一定要加v-前缀

 代码示例:

//main.js 文件import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = false// // 1. 全局注册指令
// Vue.directive('focus', {
//   // inserted 会在 指令所在的元素,被插入到页面中时触发
//   inserted (el) {
//     // el 就是指令所绑定的元素
//     // console.log(el);
//     el.focus()
//   }
// })new Vue({render: h => h(App),
}).$mount('#app')
<template><div><h1>自定义指令</h1><input v-focus ref="inp" type="text"></div>
</template><script>
export default {// mounted () {//   this.$refs.inp.focus()// }// 2. 局部注册指令directives: {// 指令名:指令的配置项focus: {inserted (el) {el.focus()}}}
}
</script><style></style>

4.指令中的配置项介绍:

inserted:被绑定元素插入父节点时调用的钩子函数

el:使用指令的那个DOM元素

5.代码示例:

需求:当页面加载时,让元素获取焦点(autofocus在safari浏览器有兼容性

6.总结:

1.自定义指令的作用是什么?

2.使用自定义指令的步骤是哪两步?

自定义指令-指令的值 

1.需求:

实现一个 color 指令 - 传入不同的颜色, 给标签设置文字颜色

2.语法:

①在绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值

<div v-color="color">我是内容</div>

②通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数

directives: {color: {inserted (el, binding) {el.style.color = binding.value},update (el, binding) {el.style.color = binding.value}}
}

3.代码示例:

<template><div><h1 v-color="color1">指令的值1测试</h1><h1 v-color="color2">指令的值2测试</h1></div>
</template><script>
export default {data () {return {color1: 'red',color2: 'orange'}},directives: {color: {// 1. inserted 提供的是元素被添加到页面中时的逻辑inserted (el, binding) {// console.log(el, binding.value);// binding.value 就是指令的值el.style.color = binding.value},// 2. update 指令的值修改的时候触发,提供值变化后,dom更新的逻辑update (el, binding) {console.log('指令的值修改了');el.style.color = binding.value}}}
}
</script><style></style>

4.📜总结:

1.通过指令的值相关语法,可以应对更复杂指令封装场景
2.指令值的语法:

① v-指令名 ="指令值",通过 等号 可以绑定指令的值

② 通过 binding.value 可以拿到指令的值

③ 通过 update 钩子,可以监听指令值的变化,进行dom更新操作


自定义指令 - v-loading 指令的封装

1.场景:

实际开发过程中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 => 用户体验不好

2.需求:

封装一个 v-loading 指令,实现加载中的效果

3.分析:

1.本质 loading效果就是一个蒙层,盖在了盒子上

2.数据请求中,开启loading状态,添加蒙层

3.数据请求完毕,关闭loading状态,移除蒙层

4.实现:

1.准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层

2.开启关闭 loading状态(添加移除蒙层),本质只需要添加移除类即可

3.结合自定义指令的语法进行封装复用

.loading:before {content: "";position: absolute;left: 0;top: 0;width: 100%;height: 100%;background: #fff url("./loading.gif") no-repeat center;
}

5.代码示例:

<template><div class="main"><div class="box" v-loading="isLoading"><ul><li v-for="item in list" :key="item.id" class="news"><div class="left"><div class="title">{{ item.title }}</div><div class="info"><span>{{ item.source }}</span><span>{{ item.time }}</span></div></div><div class="right"><img :src="item.img" alt=""></div></li></ul></div><div class="box2" v-loading="isLoading2"></div></div>
</template><script>
// 安装axios =>  yarn add axios
import axios from 'axios'// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
export default {data () {return {list: [],isLoading: true,isLoading2: true}},async created () {// 1. 发送请求获取数据const res = await axios.get('http://hmajax.itheima.net/api/news')setTimeout(() => {// 2. 更新到 list 中,用于页面渲染 v-forthis.list = res.data.datathis.isLoading = false}, 2000)},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')}}}
}
</script><style>
.loading:before {content: '';position: absolute;left: 0;top: 0;width: 100%;height: 100%;background: #fff url('./loading.gif') no-repeat center;
}.box2 {width: 400px;height: 400px;border: 2px solid #000;position: relative;
}.box {width: 800px;min-height: 500px;border: 3px solid orange;border-radius: 5px;position: relative;
}
.news {display: flex;height: 120px;width: 600px;margin: 0 auto;padding: 20px 0;cursor: pointer;
}
.news .left {flex: 1;display: flex;flex-direction: column;justify-content: space-between;padding-right: 10px;
}
.news .left .title {font-size: 20px;
}
.news .left .info {color: #999999;
}
.news .left .info span {margin-right: 20px;
}
.news .right {width: 160px;height: 120px;
}
.news .right img {width: 100%;height: 100%;object-fit: cover;
}
</style>

 📜总结:

1.通过指令相关语法,封装了指令 v-loading 实现了请求的 loading 效果
2.核心思路:
(1)准备类名 loading,通过伪元素提供遮罩层
(2)添加或移除类名,实现loading蒙层的添加移除
(3)利用指令语法,封装 v-loading 通用指令

  • inserted 钩子中,binding.value 判断指令的值,设置默认状态
  • update 钩子中,binding.value 判断指令的值,更新类名状态


二、🌟①插槽-默认插槽

1.作用:

让组件内部的一些 结构 支持 自定义

2.需求:

将需要多次显示的对话框,封装成一个组件

3.问题:

组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办??

4.插槽的基本语法:

  1. 组件内需要定制的结构部分,改用<slot></slot>占位
  2. 使用组件时, <MyDialog></MyDialog>标签内部, 传入结构替换slot
  3. 给插槽传入内容时,可以传入纯文本、HTML标签、组件

5.代码示例:

MyDialog.vue

<template><div class="dialog"><div class="dialog-header"><h3>友情提示</h3><span class="close">✖️</span></div><div class="dialog-content"><!-- 1. 在需要定制的位置,使用slot占位 --><slot></slot></div><div class="dialog-footer"><button>取消</button><button>确认</button></div></div>
</template><script>
export default {data () {return {}}
}
</script><style scoped>
* {margin: 0;padding: 0;
}
.dialog {width: 470px;height: 230px;padding: 0 25px;background-color: #ffffff;margin: 40px auto;border-radius: 5px;
}
.dialog-header {height: 70px;line-height: 70px;font-size: 20px;border-bottom: 1px solid #ccc;position: relative;
}
.dialog-header .close {position: absolute;right: 0px;top: 0px;cursor: pointer;
}
.dialog-content {height: 80px;font-size: 18px;padding: 15px 0;
}
.dialog-footer {display: flex;justify-content: flex-end;
}
.dialog-footer button {width: 65px;height: 35px;background-color: #ffffff;border: 1px solid #e1e3e9;cursor: pointer;outline: none;margin-left: 10px;border-radius: 3px;
}
.dialog-footer button:last-child {background-color: #007acc;color: #fff;
}
</style>

App.vue

<template><div><!-- 2. 在使用组件时,组件标签内填入内容 --><MyDialog><div>你确认要删除么</div></MyDialog><MyDialog><p>你确认要退出么</p></MyDialog></div>
</template><script>
import MyDialog from './components/MyDialog.vue'
export default {data () {return {}},components: {MyDialog}
}
</script><style>
body {background-color: #b3b3b3;
}
</style>

📜总结:

场景:组件内某一部分结构不确定,想要自定义怎么办

使用:插槽的步骤分为哪几步?


场景:  当组件内某一部分结构不确定,想要自定义怎么办?
        用插槽 slot占位封装
使用:  插槽使用的基本步骤?
1.先在组件内用 slot占位
2.使用组件时,传入具体标签内容插入


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

1.问题:

通过插槽完成了内容的定制,传什么显示什么, 但是如果不传,则是空白

 

能否给插槽设置 默认显示内容 呢?

2.插槽的后备内容:

封装组件时,可以为预留的`<slot>` 插槽提供后备内容(默认内容)。

3.语法:

在<slot> </slot> 标签内,放置内容, 作为默认显示内容

4.效果:

<template><div class="dialog"><div class="dialog-header"><h3>友情提示</h3><span class="close">✖️</span></div><div class="dialog-content"><!-- 往slot标签内部,编写内容,可以作为后备内容(默认值) --><slot>我是默认的文本内容</slot></div><div class="dialog-footer"><button>取消</button><button>确认</button></div></div>
</template><script>
export default {data () {return {}}
}
</script><style scoped>
* {margin: 0;padding: 0;
}
.dialog {width: 470px;height: 230px;padding: 0 25px;background-color: #ffffff;margin: 40px auto;border-radius: 5px;
}
.dialog-header {height: 70px;line-height: 70px;font-size: 20px;border-bottom: 1px solid #ccc;position: relative;
}
.dialog-header .close {position: absolute;right: 0px;top: 0px;cursor: pointer;
}
.dialog-content {height: 80px;font-size: 18px;padding: 15px 0;
}
.dialog-footer {display: flex;justify-content: flex-end;
}
.dialog-footer button {width: 65px;height: 35px;background-color: #ffffff;border: 1px solid #e1e3e9;cursor: pointer;outline: none;margin-left: 10px;border-radius: 3px;
}
.dialog-footer button:last-child {background-color: #007acc;color: #fff;
}
</style>
<template><div><MyDialog></MyDialog><MyDialog>你确认要退出么</MyDialog></div>
</template><script>
import MyDialog from './components/MyDialog.vue'
export default {data () {return {}},components: {MyDialog}
}
</script><style>
body {background-color: #b3b3b3;
}
</style>

📜总结:

如何给插槽设置默认显示内容?
在slot标签内,写好后备内容。


什么时候插槽后备内容会显示?
当使用组件并未给我们传入具体标签或内容时


③插槽-具名插槽 

1.需求:

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

 上面的弹框中有三处不同,但是默认插槽只能定制一个位置,这时候怎么办呢?

 

2.具名插槽语法:

  • 多个 slot 使用 name 属性区分名字

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

3.v-slot的简写:

v-slot写起来太长,VUE提供一个简单写法 v-slot —> #

4.📜总结:

  • 组件内 有多处不确定的结构 怎么办?
  • 具名插槽的语法是什么?
  • v-slot:插槽名可以简化成什么?

组件内 有多处不确定的结构 怎么办?
具名插槽
        1.slot 占位,给name属性起名字来区分
        2.template 配合 v-slot:插槽名 分发内容
v-slot:插槽名 可以简化成什么?
#插槽名

代码示例:

<template><div><MyDialog><!-- 需要通过template标签包裹需要分发的结构,包成一个整体 --><template v-slot:head><div>我是大标题</div></template><template v-slot:content><div>我是内容</div></template><template #footer><button>取消</button><button>确认</button></template></MyDialog></div>
</template><script>
import MyDialog from './components/MyDialog.vue'
export default {data () {return {}},components: {MyDialog}
}
</script><style>
body {background-color: #b3b3b3;
}
</style>
<template><div class="dialog"><div class="dialog-header"><!-- 一旦插槽起了名字,就是具名插槽,只支持定向分发 --><slot name="head"></slot></div><div class="dialog-content"><slot name="content"></slot></div><div class="dialog-footer"><slot name="footer"></slot></div></div>
</template><script>
export default {data () {return {}}
}
</script><style scoped>
* {margin: 0;padding: 0;
}
.dialog {width: 470px;height: 230px;padding: 0 25px;background-color: #ffffff;margin: 40px auto;border-radius: 5px;
}
.dialog-header {height: 70px;line-height: 70px;font-size: 20px;border-bottom: 1px solid #ccc;position: relative;
}
.dialog-header .close {position: absolute;right: 0px;top: 0px;cursor: pointer;
}
.dialog-content {height: 80px;font-size: 18px;padding: 15px 0;
}
.dialog-footer {display: flex;justify-content: flex-end;
}
.dialog-footer button {width: 65px;height: 35px;background-color: #ffffff;border: 1px solid #e1e3e9;cursor: pointer;outline: none;margin-left: 10px;border-radius: 3px;
}
.dialog-footer button:last-child {background-color: #007acc;color: #fff;
}
</style>


④作用域插槽

1.插槽分类:

  • 默认插槽 (组件内定制一处结构)

  • 具名插槽 (组件内定制多处结构)

插槽只有两种,作用域插槽不属于插槽的一种分类(作用域槽插槽的一个传参语法)

2.作用:

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

3.场景:

封装表格组件实现思路: 

1.父传子,动态渲染表格内容

2.利用默认插槽,定制操作列 

3.删除或查看都需要用到 当前项的 id,属于 组件内部的数据——通过 作用域插槽 传值绑定,进而使用

4.使用步骤:

1.给 slot 标签, 以 添加属性的方式传值

<slot :id="item.id" msg="测试文本"></slot><slot :id="item.id" msg="测试文本"></slot>

2.所有添加的属性, 都会被收集到一个对象中

{ id: 3, msg: '测试文本' }

3.在template中, 通过 #插槽名= "obj" 接收,默认插槽名为 default

<MyTable :list="list"><template #default="obj"><button @click="del(obj.id)">删除</button></template>
</MyTable>

5.代码示例:

App.vue 

<template><div><MyTable :data="list"><!-- 3. 通过template #插槽名="变量名" 接收 --><template #default="obj"><button @click="del(obj.row.id)">删除</button></template></MyTable><MyTable :data="list2"><template #default="{ row }"><button @click="show(row)">查看</button></template></MyTable></div>
</template><script>
import MyTable from './components/MyTable.vue'
export default {data () {return {list: [{ id: 1, name: '张小花', age: 18 },{ id: 2, name: '孙大明', age: 19 },{ id: 3, name: '刘德忠', age: 17 },],list2: [{ id: 1, name: '赵小云', age: 18 },{ id: 2, name: '刘蓓蓓', age: 19 },{ id: 3, name: '姜肖泰', age: 17 },]}},methods: {del (id) {this.list = this.list.filter(item => item.id !== id)},show (row) {// console.log(row);alert(`姓名:${row.name}; 年纪:${row.age}`)}},components: {MyTable}
}
</script>

MyTable.vue

<template><table class="my-table"><thead><tr><th>序号</th><th>姓名</th><th>年纪</th><th>操作</th></tr></thead><tbody><tr v-for="(item, index) in data" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td>{{ item.age }}</td><td><!-- 1. 给slot标签,添加属性的方式传值 --><slot :row="item" msg="测试文本"></slot><!-- 2. 将所有的属性,添加到一个对象中 --><!-- {row: { id: 2, name: '孙大明', age: 19 },msg: '测试文本'}--></td></tr></tbody></table>
</template><script>
export default {props: {data: Array}
}
</script><style scoped>
.my-table {width: 450px;text-align: center;border: 1px solid #ccc;font-size: 24px;margin: 30px auto;
}
.my-table thead {background-color: #1f74ff;color: #fff;
}
.my-table thead th {font-weight: normal;
}
.my-table thead tr {line-height: 40px;
}
.my-table th,
.my-table td {border-bottom: 1px solid #ccc;border-right: 1px solid #ccc;
}
.my-table td:last-child {border-right: none;
}
.my-table tr:last-child td {border-bottom: none;
}
.my-table button {width: 65px;height: 35px;font-size: 18px;border: 1px solid #ccc;outline: none;border-radius: 3px;cursor: pointer;background-color: #ffffff;margin-left: 5px;
}
</style>

6.📜总结:

1.作用域插槽的作用是什么?

可以给插槽上绑定数据,供将来使用组件时使用

2.作用域插槽的使用步骤是什么?

(1)给 slot 标签以添加属性的方式传值
(2)所有属性都会被收集到一个对象中
(3)template 中,通过 `#插槽名="obj"` 接收


🌟综合案例 - 商品列表-MyTag组件抽离

1.需求说明

①my-tag 标签组件封装

​ (1) 双击显示输入框,输入框获取焦点

​ (2) 失去焦点,隐藏输入框

​ (3) 回显标签信息

​ (4) 内容修改,回车 → 修改标签信息

②my-table 表格组件封装

​ (1) 动态传递表格数据渲染

​ (2) 表头支持用户自定义

​ (3) 主体支持用户自定义

代码准备如下:

<template><div class="table-case"><table class="my-table"><thead><tr><th>编号</th><th>名称</th><th>图片</th><th width="100px">标签</th></tr></thead><tbody><tr><td>1</td><td>梨皮朱泥三绝清代小品壶经典款紫砂壶</td><td><img src="https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg" /></td><td><div class="my-tag"><!-- <input class="input"type="text"placeholder="输入标签"/> --><div class="text">茶具</div></div></td></tr><tr><td>1</td><td>梨皮朱泥三绝清代小品壶经典款紫砂壶</td><td><img src="https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg" /></td><td><div class="my-tag"><!-- <inputref="inp"class="input"type="text"placeholder="输入标签"/> --><div class="text">男靴</div></div></td></tr></tbody></table></div>
</template><script>
export default {name: 'TableCase',components: {},data() {return {goods: [{id: 101,picture:'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg',name: '梨皮朱泥三绝清代小品壶经典款紫砂壶',tag: '茶具',},{id: 102,picture:'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg',name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌',tag: '男鞋',},{id: 103,picture:'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png',name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm',tag: '儿童服饰',},{id: 104,picture:'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg',name: '基础百搭,儿童套头针织毛衣1-9岁',tag: '儿童服饰',},],}},
}
</script><style lang="less" scoped>
.table-case {width: 1000px;margin: 50px auto;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}.my-table {width: 100%;border-spacing: 0;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}th {background: #f5f5f5;border-bottom: 2px solid #069;}td {border-bottom: 1px dashed #ccc;}td,th {text-align: center;padding: 10px;transition: all 0.5s;&.red {color: red;}}.none {height: 100px;line-height: 100px;color: #999;}}.my-tag {cursor: pointer;.input {appearance: none;outline: none;border: 1px solid #ccc;width: 100px;height: 40px;box-sizing: border-box;padding: 10px;color: #666;&::placeholder {color: #666;}}}
}
</style>


2.my-tag组件封装-创建组件

MyTag.vue 

<template><div class="my-tag"><!--  <inputclass="input"type="text"placeholder="输入标签" /> --><div  class="text">茶具</div></div>
</template><script>
export default {}
</script><style lang="less" scoped>
.my-tag {cursor: pointer;.input {appearance: none;outline: none;border: 1px solid #ccc;width: 100px;height: 40px;box-sizing: border-box;padding: 10px;color: #666;&::placeholder {color: #666;}}
}
</style>

 App.vue

<template>...<tbody><tr>....<td><MyTag></MyTag></td></tr></tbody>...
</template>
<script>
import MyTag from './components/MyTag.vue'
export default {name: 'TableCase',components: {MyTag,},....</script>


3.MyTag组件控制显示隐藏

MyTag.vue 

<template><div class="my-tag"><inputv-if="isEdit"v-focusref="inp"class="input"type="text"placeholder="输入标签" @blur="isEdit = false" /><div v-else@dblclick="handleClick"class="text">茶具</div></div>
</template><script>
export default {data () {return {isEdit: false}},methods: {handleClick () {this.isEdit = true}}
}
</script> 

 main.js

// 封装全局指令 focus
Vue.directive('focus', {// 指令所在的dom元素,被插入到页面中时触发inserted (el) {el.focus()}
})

4.MyTag组件进行 v-model 绑定

 App.vue

<MyTag v-model="tempText"></MyTag>
<script>export default {data(){tempText:'水杯'}}
</script>

 MyTag.vue

<template><div class="my-tag"><inputv-if="isEdit"v-focusref="inp"class="input"type="text"placeholder="输入标签":value="value"@blur="isEdit = false"@keyup.enter="handleEnter"/><div v-else@dblclick="handleClick"class="text">{{ value }}</div></div>
</template><script>
export default {props: {value: String},data () {return {isEdit: false}},methods: {handleClick () {this.isEdit = true},handleEnter (e) {// 非空处理if (e.target.value.trim() === '') return alert('标签内容不能为空')this.$emit('input', e.target.value)// 提交完成,关闭输入状态this.isEdit = false}}
}
</script> 


5.封装MyTable组件-动态渲染数据

 App.vue

<template><div class="table-case"><MyTable :data="goods"></MyTable></div>
</template><script>
import MyTable from './components/MyTable.vue'
export default {name: 'TableCase',components: { MyTable},data(){return {....}},
}
</script> 

MyTable.vue

<template><table class="my-table"><thead><tr><th>编号</th><th>名称</th><th>图片</th><th width="100px">标签</th></tr></thead><tbody><tr v-for="(item, index) in data" :key="item.id"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td><img:src="item.picture"/></td><td>标签内容<!-- <MyTag v-model="item.tag"></MyTag> --></td></tr></tbody></table>
</template><script>
export default {props: {data: {type: Array,required: true}}
};
</script><style lang="less" scoped>.my-table {width: 100%;border-spacing: 0;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}th {background: #f5f5f5;border-bottom: 2px solid #069;}td {border-bottom: 1px dashed #ccc;}td,th {text-align: center;padding: 10px;transition: all .5s;&.red {color: red;}}.none {height: 100px;line-height: 100px;color: #999;}
}</style>

6.综合案例-封装MyTable组件-自定义结构

App.vue

<template><div class="table-case"><MyTable :data="goods"><template #head><th>编号</th><th>名称</th><th>图片</th><th width="100px">标签</th></template><template #body="{ item, index }"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td><img:src="item.picture"/></td><td><MyTag v-model="item.tag"></MyTag></td></template></MyTable></div>
</template><script>
import MyTag from './components/MyTag.vue'
import MyTable from './components/MyTable.vue'
export default {name: 'TableCase',components: {MyTag,MyTable},data () {return {....}
}
</script>

 MyTable.vue

<template><table class="my-table"><thead><tr><slot name="head"></slot></tr></thead><tbody><tr v-for="(item, index) in data" :key="item.id"><slot name="body" :item="item" :index="index" ></slot></tr></tbody></table>
</template><script>
export default {props: {data: {type: Array,required: true}}
};
</script>

 📜总结:

①商品列表的实现封装了几个组件?
        2个组件,标签组件和表格组件
②封装用到的核心技术点有哪些?
(1)props父传子 $emit子传父 V-model
(2)$nextTick 自定义指令
(3)插槽: 具名插槽,作用域插槽

总代码如下:

App.vue

<template><div class="table-case"><MyTable :data="goods"><template #head><th>编号</th><th>名称</th><th>图片</th><th width="100px">标签</th></template><template #body="{ item, index }"><td>{{ index + 1 }}</td><td>{{ item.name }}</td><td><img:src="item.picture"/></td><td><MyTag v-model="item.tag"></MyTag></td></template></MyTable></div>
</template><script>
// my-tag 标签组件的封装
// 1. 创建组件 - 初始化
// 2. 实现功能
//    (1) 双击显示,并且自动聚焦
//        v-if v-else @dbclick 操作 isEdit
//        自动聚焦:
//        1. $nextTick => $refs 获取到dom,进行focus获取焦点
//        2. 封装v-focus指令//    (2) 失去焦点,隐藏输入框
//        @blur 操作 isEdit 即可//    (3) 回显标签信息
//        回显的标签信息是父组件传递过来的
//        v-model实现功能 (简化代码)  v-model => :value 和 @input
//        组件内部通过props接收, :value设置给输入框//    (4) 内容修改了,回车 => 修改标签信息
//        @keyup.enter, 触发事件 $emit('input', e.target.value)// ---------------------------------------------------------------------// my-table 表格组件的封装
// 1. 数据不能写死,动态传递表格渲染的数据  props
// 2. 结构不能写死 - 多处结构自定义 【具名插槽】
//    (1) 表头支持自定义
//    (2) 主体支持自定义import MyTag from './components/MyTag.vue'
import MyTable from './components/MyTable.vue'
export default {name: 'TableCase',components: {MyTag,MyTable},data () {return {// 测试组件功能的临时数据tempText: '水杯',tempText2: '钢笔',goods: [{ id: 101, picture: 'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具' },{ id: 102, picture: 'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋' },{ id: 103, picture: 'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰' },{ id: 104, picture: 'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰' },]}}
}
</script><style lang="less" scoped>
.table-case {width: 1000px;margin: 50px auto;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}
}</style>

 MyTable.vue

<template><table class="my-table"><thead><tr><slot name="head"></slot></tr></thead><tbody><tr v-for="(item, index) in data" :key="item.id"><slot name="body" :item="item" :index="index" ></slot></tr></tbody></table>
</template><script>
export default {props: {data: {type: Array,required: true}}
};
</script><style lang="less" scoped>.my-table {width: 100%;border-spacing: 0;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}th {background: #f5f5f5;border-bottom: 2px solid #069;}td {border-bottom: 1px dashed #ccc;}td,th {text-align: center;padding: 10px;transition: all .5s;&.red {color: red;}}.none {height: 100px;line-height: 100px;color: #999;}
}</style>

 MyTag.vue

<template><div class="my-tag"><inputv-if="isEdit"v-focusref="inp"class="input"type="text"placeholder="输入标签":value="value"@blur="isEdit = false"@keyup.enter="handleEnter"/><div v-else@dblclick="handleClick"class="text">{{ value }}</div></div>
</template><script>
export default {props: {value: String},data () {return {isEdit: false}},methods: {handleClick () {// 双击后,切换到显示状态 (Vue是异步dom更新)this.isEdit = true// // 等dom更新完了,再获取焦点// this.$nextTick(() => {//   // 立刻获取焦点//   this.$refs.inp.focus()// })},handleEnter (e) {// 非空处理if (e.target.value.trim() === '') return alert('标签内容不能为空')// 子传父,将回车时,[输入框的内容] 提交给父组件更新// 由于父组件是v-model,触发事件,需要触发 input 事件this.$emit('input', e.target.value)// 提交完成,关闭输入状态this.isEdit = false}}
}
</script><style lang="less" scoped>
.my-tag {cursor: pointer;.input {appearance: none;outline: none;border: 1px solid #ccc;width: 100px;height: 40px;box-sizing: border-box;padding: 10px;color: #666;&::placeholder {color: #666;}}
}
</style>


三、单页应用程序介绍

1.概念:

单页应用程序:SPA【Single Page Application】是指所有的功能都在一个html页面上实现

2.具体示例:

单页应用网站: 网易云音乐 网易云音乐

多页应用网站:京东 京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!

 3.单页应用 VS 多页面应用:

  • 单页应用类网站:系统类网站 / 内部网站 / 文档类网站 / 移动端站点
  • 多页应用类网站:公司官网 / 电商类网站

4.总结:

1.什么是单页面应用程序?

所有功能在一个 HTML 页面上实现

2.单页面应用优缺点?

优点: 按需更新性能高,开发效率高,用户体验好

缺点: 学习成本,首屏加载慢,不利于SEO

3.单页应用场景?

系统类网站 / 内部网站 / 文档类网站 / 移动端站点


1.路由介绍

1.思考:

单页面应用程序,之所以开发效率高,性能好,用户体验好

最大的原因就是:页面按需更新

比如当点击【发现音乐】和【关注】时,只是更新下面部分内容,对于头部是不更新的

要按需更新,首先就需要明确:访问路径和 组件的对应关系!

访问路径 和 组件的对应关系如何确定呢? 路由

2.路由的介绍

生活中的路由:设备和ip的映射关系

 

Vue中的路由:路径和组件映射关系

3.总结: 

  • 什么是路由

路由是一种映射关系

  • Vue中的路由是什么

 路径组件 的映射关系
根据路由就能知道不同路径的,应该匹配渲染哪个组件


四、路由的基本使用

1.目标

认识插件 VueRouter,掌握 VueRouter 的基本使用步骤

 

2.作用

修改地址栏路径时,切换显示匹配的组件

3.说明

Vue 官方的一个路由插件,是一个第三方包

4.官网

Vue RouterVue.js 官方的路由管理器。https://v3.router.vuejs.org/zh/

5.VueRouter的使用(5+2)

固定5个固定的步骤(不用死背,熟能生巧)

①下载 VueRouter 模块到当前工程,版本3.6.5

yarn add vue-router@3.6.5

②main.js 中引入VueRouter

import VueRouter from 'vue-router'

③安装注册

Vue.use(VueRouter)

④创建路由对象

const router = new VueRouter()

⑤注入,将路由对象注入到new Vue实例中,建立关联

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

当配置完以上5步之后 就可以看到浏览器地址栏中的路由 变成了 /#/的形式。表示项目的路由已经被Vue-Router管理了 

两个核心步骤

  1. 创建需要的组件 (views目录),配置路由规则

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

App.vue

<div class="footer_wrap"><a href="#/find">发现音乐</a><a href="#/my">我的音乐</a><a href="#/friend">朋友</a>
</div>
<div class="top"><router-view></router-view>
</div>

📜总结:

1.如何实现 路径改变,对应组件 切换,应该使用哪个插件?

Vue 官方插件 VueRouter

2.Vue-Router的使用步骤是什么(5+2)?

5个基础步骤:

  1. 下包
  2. 引入
  3. Vueuse 安装注册
  4. 创建路由对象
  5. 注入Vue实例

2个核心步骤:

  1. 创建组件,配置规则(路径组件的匹配关系)
  2. 配导航,配置路由出口 router-view(组件展示的位置)

代码演示:

import Vue from 'vue'
import App from './App.vue'// 路由的使用步骤 5 + 2
// 5个基础步骤
// 1. 下载 v3.6.5
// 2. 引入
// 3. 安装注册 Vue.use(Vue插件)
// 4. 创建路由对象
// 5. 注入到new Vue中,建立关联// 2个核心步骤
// 1. 建组件(views目录),配规则
// 2. 准备导航链接,配置路由出口(匹配的组件展示的位置) 
import Find from './views/Find'
import My from './views/My'
import Friend from './views/Friend'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化const router = new VueRouter({// routes 路由规则们// route  一条路由规则 { path: 路径, component: 组件 }routes: [{ path: '/find', component: Find },{ path: '/my', component: My },{ path: '/friend', component: Friend },]
})Vue.config.productionTip = falsenew Vue({render: h => h(App),router
}).$mount('#app')

App.vue

<template><div><div class="footer_wrap"><a href="#/find">发现音乐</a><a href="#/my">我的音乐</a><a href="#/friend">朋友</a></div><div class="top"><!-- 路由出口 → 匹配的组件所展示的位置 --><router-view></router-view></div></div>
</template><script>
export default {};
</script><style>
body {margin: 0;padding: 0;
}
.footer_wrap {position: relative;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;
}
</style>

views下的文件

<template><div><p>我的音乐</p><p>我的音乐</p><p>我的音乐</p><p>我的音乐</p></div>
</template><script>
export default {name: 'MyMusic'
}
</script><style></style><template><div><p>我的朋友</p><p>我的朋友</p><p>我的朋友</p><p>我的朋友</p></div>
</template><script>
export default {name: 'MyFriend'
}
</script><style></style>

组件的存放目录问题

注意: .vue文件 本质无区别

1.组件分类:

.vue文件分为2类,都是 .vue文件(本质无区别)

  • 页面组件 (配置路由规则时使用的组件)
  • 复用组件(多个组件中都使用到的组件)

2.存放目录:

分类开来的目的就是为了 更易维护

  1. src/views文件夹

    页面组件 - 页面展示 - 配合路由用

  2. src/components文件夹

    复用组件 - 展示数据 - 常用于复用

小练习: 以下.vue 文件,属于什么分类组件?应该放在哪个目录?

页面组件 配合路由用

放在 views目录

使用多次——复用组件 放在 components 目录

3.总结:

  • 组件分类有哪两类?分类的目的?  页面组件和复用组件,便于维护
  • 不同分类的组件应该放在什么文件夹?作用分别是什么?  
  1. 页面组件 - views文件夹 =>配合路由,页面展示
  2. 复用组件- components文件夹,=>封装复用

以上为Day5 学习内容,谢谢!

这篇关于Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801515

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

如何解决Pycharm编辑内容时有光标的问题

《如何解决Pycharm编辑内容时有光标的问题》文章介绍了如何在PyCharm中配置VimEmulator插件,包括检查插件是否已安装、下载插件以及安装IdeaVim插件的步骤... 目录Pycharm编辑内容时有光标1.如果Vim Emulator前面有对勾2.www.chinasem.cn如果tools工

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

C#比较两个List集合内容是否相同的几种方法

《C#比较两个List集合内容是否相同的几种方法》本文详细介绍了在C#中比较两个List集合内容是否相同的方法,包括非自定义类和自定义类的元素比较,对于非自定义类,可以使用SequenceEqual、... 目录 一、非自定义类的元素比较1. 使用 SequenceEqual 方法(顺序和内容都相等)2.

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...