Vue(4)

server/2025/2/8 19:44:00/

一.组件的三大组成部分-注意点说明

在这里插入图片描述

(1)scoped样式冲突

默认情况:写在组件中的样式会全局生效 → 因此很容易造成多个组件之间的样式冲突

①全局样式:默认组件中的样式会作用到全局
②局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件

<template><div class="base-one">BaseOne</div>
</template><script>
export default {}
</script><style scoped>
/* 1.style中的样式 默认是作用到全局的2.加上scoped可以让样式变成局部样式组件都应该有独立的样式,推荐加scoped(原理)-----------------------------------------------------scoped原理:1.给当前组件模板的所有元素,都会添加上一个自定义属性data-v-hash值data-v-5f6a9d56  用于区分开不通的组件2.css选择器后面,被自动处理,添加上了属性选择器div[data-v-5f6a9d56]
*/
div{border: 3px solid blue;margin: 30px;
}
</style>
<template><div class="base-one">BaseTwo</div>
</template><script>
export default {}
</script><style scoped>div{border: 3px solid red;margin: 30px;}
</style>

(2)data一个函数

一个组件的data选项必须是一个函数 → 保证每个各组件实例,维护独立的一份数据对象
每次创建新的组件实例,都会新执行一次data函数,得到一个新对象

<template><div class="base-count"><button @click="count--">-</button><span>{{ count }}</span><button @click="count++">+</button></div>
</template><script>
export default {// data() {//   console.log('函数执行了')//   return {//     count: 100,//   }// },data: function () {return {count: 100,}},
}
</script><style>
.base-count {margin: 20px;
}
</style>

(3)什么是组件通信

组件通信,就是指组件与组件之前的数据传递
组件的数据的独立的,无法直接访问其他组件的数据
想用其他组件的数据 → 组件通信

不同组件关系和组件通信方案分类

组件关系分类
1.父子关系 2.非父子关系

组件通信解决方案

父子通信流程图:
1.父组件通过props将数据传递给子组件

<template><div class="son" style="border:3px solid #000;margin:10px"><!-- 3.直接使用props的值 -->我是Son组件 {{title}}</div>
</template><script>
export default {name: 'Son-Child',// 2.通过props来接受props:['title']
}
</script><style></style>
<template><div class="app" style="border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签,添加属性方式 赋值 --><Son :title="myTitle"></Son></div>
</template><script>
import Son from './components/Son.vue'
export default {name: 'App',data() {return {myTitle: '学前端,就来黑马程序员',}},components: {Son,},
}
</script><style>
</style>

2.子组件利用$emit通知父组件修改更新

<template><div class="son" style="border: 3px solid #000; margin: 10px">我是Son组件 {{ title }}<button @click="changeFn">修改title</button></div>
</template><script>
export default {name: 'Son-Child',props: ['title'],methods: {changeFn() {// 通过this.$emit() 向父组件发送通知this.$emit('changTitle','传智教育')},},
}
</script><style>
</style>
<template><div class="app" style="border: 3px solid #000; margin: 10px">我是APP组件<!-- 2.父组件对子组件的消息进行监听 --><Son :title="myTitle" @changTitle="handleChange"></Son></div>
</template><script>
import Son from './components/Son.vue'
export default {name: 'App',data() {return {myTitle: '学前端,就来黑马程序员',}},components: {Son,},methods: {// 3.提供处理函数,提供逻辑handleChange(newTitle) {this.myTitle = newTitle},},
}
</script><style>
</style>

在这里插入图片描述

二.props讲解

prop定义:组件上注册的一些自定义属性
prop作用:向子组件传递数据

<template><div class="userinfo"><h3>我是个人信息组件</h3><div>姓名:{{username}}</div><div>年龄:{{age}}</div><div>是否单身:{{isSingle}}</div><div>座驾:{{car.brand}}</div><div>兴趣爱好:{{hobby.join('、')}}</div></div>
</template><script>
export default {props:['username','age','isSingle','car','hobby']
}
</script><style>
.userinfo {width: 300px;border: 3px solid #000;padding: 20px;
}
.userinfo > div {margin: 20px 10px;
}
</style>
<template><div class="app"><UserInfo:username="username":age="age":isSingle="isSingle":car="car":hobby="hobby"></UserInfo></div>
</template><script>
import UserInfo from './components/UserInfo.vue'
export default {data() {return {username: '小帅',age: 28,isSingle: true,car: {brand: '宝马',},hobby: ['篮球', '足球', '羽毛球'],}},components: {UserInfo,},
}
</script><style>
</style>

props校验:为组件的prop指定验证要求,不符合要求,控制带就会有错误提示 → 帮助开发者,快速发现错误

语法:

props:{校验的属性名:类型}

①类型校验
②非空校验

<template><div class="base-progress"><div class="inner" :style="{ width: w + '%' }"><span>{{ w }}%</span></div></div>
</template><script>
export default {// 1.基础写法(类型校验)// props: {//   w: Number,// },// 2.完整写法(类型、默认值、非空、自定义校验)props: {w: {type: Number,required: true,default: 0,validator(val) {// console.log(val)if (val >= 100 || val <= 0) {console.error('传入的范围必须是0-100之间')return false} else {return true}},},},
}
</script><style scoped>
.base-progress {height: 26px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;
}
.inner {position: relative;background: #379bff;border-radius: 15px;height: 25px;box-sizing: border-box;left: -3px;top: -2px;
}
.inner span {position: absolute;right: 0;top: 26px;
}
</style>

③默认值

<template><div class="base-progress"><div class="inner" :style="{ width: w + '%' }"><span>{{ w }}%</span></div></div>
</template><script>
export default {props: {w: Number,},
}
</script><style scoped>
.base-progress {height: 26px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;
}
.inner {position: relative;background: #379bff;border-radius: 15px;height: 25px;box-sizing: border-box;left: -3px;top: -2px;
}
.inner span {position: absolute;right: 0;top: 26px;
}
</style>
<template><div class="app"><BaseProgress :w="width"></BaseProgress></div>
</template><script>
import BaseProgress from './components/BaseProgress.vue'
export default {data() {return {width: 30,}},components: {BaseProgress,},
}
</script><style>
</style>

④自定义校验

props:{校验的属性名:{type:类型,required:true,default:默认值,validator(value){return 是否通过校验}}}

prop & data、单向数据流

共同点:都可以给组件提供数据
区别:
data的数据是自己的 → 随便改
prop的数据是外部的 → 不能直接改,要遵循单向数据流

<template><div class="base-count"><button @click="handleSub">-</button><span>{{ count }}</span><button @click="handleAdd">+</button></div>
</template><script>
export default {// 1.自己的数据随便修改  (谁的数据 谁负责)// data () {//   return {//     count: 100,//   }// },// 2.外部传过来的数据 不能随便修改props: {count: {type: Number,},},methods: {handleSub() {this.$emit('changeCount', this.count - 1)},handleAdd() {this.$emit('changeCount', this.count + 1)},},
}
</script><style>
.base-count {margin: 20px;
}
</style>

组件通信案例:小黑记事本 - 组件版

TodoFooter.vue

<template><!-- 统计和清空 --><footer class="footer"><!-- 统计 --><span class="todo-count">合 计:<strong> {{ list.length }} </strong></span><!-- 清空 --><button class="clear-completed" @click="clear">清空任务</button></footer>
</template><script>
export default {props: {list: {type: Array,},},methods:{clear(){this.$emit('clear')}}
}
</script><style>
</style>

TodoHeader

<template><!-- 输入框 --><header class="header"><h1>小黑记事本</h1><input placeholder="请输入任务" class="new-todo" v-model="todoName" @keyup.enter="handleAdd"/><button class="add" @click="handleAdd">添加任务</button></header>
</template><script>
export default {data(){return {todoName:''}},methods:{handleAdd(){// console.log(this.todoName)this.$emit('add',this.todoName)this.todoName = ''}}
}
</script><style></style>

TodoMain.vue

<template><!-- 列表区域 --><section class="main"><ul class="todo-list"><li class="todo" v-for="(item, index) in list" :key="item.id"><div class="view"><span class="index">{{ index + 1 }}.</span><label>{{ item.name }}</label><button class="destroy" @click="handleDel(item.id)"></button></div></li></ul></section>
</template><script>
export default {props: {list: {type: Array,},},methods: {handleDel(id) {this.$emit('del', id)},},
}
</script><style>
</style>

APP.vue

<template><!-- 主体区域 --><section id="app"><TodoHeader @add="handleAdd"></TodoHeader><TodoMain :list="list" @del="handelDel"></TodoMain><TodoFooter :list="list" @clear="clear"></TodoFooter></section>
</template><script>
import TodoHeader from './components/TodoHeader.vue'
import TodoMain from './components/TodoMain.vue'
import TodoFooter from './components/TodoFooter.vue'// 渲染功能:
// 1.提供数据: 提供在公共的父组件 App.vue
// 2.通过父传子,将数据传递给TodoMain
// 3.利用 v-for渲染// 添加功能:
// 1.手机表单数据  v-model
// 2.监听事件(回车+点击都要添加)
// 3.子传父,讲任务名称传递给父组件 App.vue
// 4.进行添加 unshift(自己的数据自己负责)
// 5.清空文本框输入的内容
// 6.对输入的空数据 进行判断// 删除功能
// 1.监听事件(监听删除的点击) 携带id
// 2.子传父,讲删除的id传递给父组件的App.vue
// 3.进行删除filter(自己的数据 自己负责)// 底部合计:父传子  传list 渲染
// 清空功能:子传父  通知父组件 → 父组件进行更新
// 持久化存储:watch深度监视list的变化 -> 往本地存储 ->进入页面优先读取本地数据
export default {data() {return {list: JSON.parse(localStorage.getItem('list')) || [{ id: 1, name: '打篮球' },{ id: 2, name: '看电影' },{ id: 3, name: '逛街' },],}},components: {TodoHeader,TodoMain,TodoFooter,},watch: {list: {deep: true,handler(newVal) {localStorage.setItem('list', JSON.stringify(newVal))},},},methods: {handleAdd(todoName) {// console.log(todoName)this.list.unshift({id: +new Date(),name: todoName,})},handelDel(id) {// console.log(id);this.list = this.list.filter((item) => item.id !== id)},clear() {this.list = []},},
}
</script><style>
html,
body {margin: 0;padding: 0;
}
body {background: #fff;
}
button {margin: 0;padding: 0;border: 0;background: none;font-size: 100%;vertical-align: baseline;font-family: inherit;font-weight: inherit;color: inherit;-webkit-appearance: none;appearance: none;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}body {font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;line-height: 1.4em;background: #f5f5f5;color: #4d4d4d;min-width: 230px;max-width: 550px;margin: 0 auto;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;font-weight: 300;
}:focus {outline: 0;
}.hidden {display: none;
}#app {background: #fff;margin: 180px 0 40px 0;padding: 15px;position: relative;box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#app .header input {border: 2px solid rgba(175, 47, 47, 0.8);border-radius: 10px;
}
#app .add {position: absolute;right: 15px;top: 15px;height: 68px;width: 140px;text-align: center;background-color: rgba(175, 47, 47, 0.8);color: #fff;cursor: pointer;font-size: 18px;border-radius: 0 10px 10px 0;
}#app input::-webkit-input-placeholder {font-style: italic;font-weight: 300;color: #e6e6e6;
}#app input::-moz-placeholder {font-style: italic;font-weight: 300;color: #e6e6e6;
}#app input::input-placeholder {font-style: italic;font-weight: 300;color: gray;
}#app h1 {position: absolute;top: -120px;width: 100%;left: 50%;transform: translateX(-50%);font-size: 60px;font-weight: 100;text-align: center;color: rgba(175, 47, 47, 0.8);-webkit-text-rendering: optimizeLegibility;-moz-text-rendering: optimizeLegibility;text-rendering: optimizeLegibility;
}.new-todo,
.edit {position: relative;margin: 0;width: 100%;font-size: 24px;font-family: inherit;font-weight: inherit;line-height: 1.4em;border: 0;color: inherit;padding: 6px;box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);box-sizing: border-box;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}.new-todo {padding: 16px;border: none;background: rgba(0, 0, 0, 0.003);box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}.main {position: relative;z-index: 2;
}.todo-list {margin: 0;padding: 0;list-style: none;overflow: hidden;
}.todo-list li {position: relative;font-size: 24px;height: 60px;box-sizing: border-box;border-bottom: 1px solid #e6e6e6;
}.todo-list li:last-child {border-bottom: none;
}.todo-list .view .index {position: absolute;color: gray;left: 10px;top: 20px;font-size: 22px;
}.todo-list li .toggle {text-align: center;width: 40px;/* auto, since non-WebKit browsers doesn't support input styling */height: auto;position: absolute;top: 0;bottom: 0;margin: auto 0;border: none; /* Mobile Safari */-webkit-appearance: none;appearance: none;
}.todo-list li .toggle {opacity: 0;
}.todo-list li .toggle + label {/*Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/*/background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');background-repeat: no-repeat;background-position: center left;
}.todo-list li .toggle:checked + label {background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}.todo-list li label {word-break: break-all;padding: 15px 15px 15px 60px;display: block;line-height: 1.2;transition: color 0.4s;
}.todo-list li.completed label {color: #d9d9d9;text-decoration: line-through;
}.todo-list li .destroy {display: none;position: absolute;top: 0;right: 10px;bottom: 0;width: 40px;height: 40px;margin: auto 0;font-size: 30px;color: #cc9a9a;margin-bottom: 11px;transition: color 0.2s ease-out;
}.todo-list li .destroy:hover {color: #af5b5e;
}.todo-list li .destroy:after {content: '×';
}.todo-list li:hover .destroy {display: block;
}.todo-list li .edit {display: none;
}.todo-list li.editing:last-child {margin-bottom: -1px;
}.footer {color: #777;padding: 10px 15px;height: 20px;text-align: center;border-top: 1px solid #e6e6e6;
}.footer:before {content: '';position: absolute;right: 0;bottom: 0;left: 0;height: 50px;overflow: hidden;box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,0 17px 2px -6px rgba(0, 0, 0, 0.2);
}.todo-count {float: left;text-align: left;
}.todo-count strong {font-weight: 300;
}.filters {margin: 0;padding: 0;list-style: none;position: absolute;right: 0;left: 0;
}.filters li {display: inline;
}.filters li a {color: inherit;margin: 3px;padding: 3px 7px;text-decoration: none;border: 1px solid transparent;border-radius: 3px;
}.filters li a:hover {border-color: rgba(175, 47, 47, 0.1);
}.filters li a.selected {border-color: rgba(175, 47, 47, 0.2);
}.clear-completed,
html .clear-completed:active {float: right;position: relative;line-height: 20px;text-decoration: none;cursor: pointer;
}.clear-completed:hover {text-decoration: underline;
}.info {margin: 50px auto 0;color: #bfbfbf;font-size: 15px;text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);text-align: center;
}.info p {line-height: 1;
}.info a {color: inherit;text-decoration: none;font-weight: 400;
}.info a:hover {text-decoration: underline;
}/*Hack to remove background from Mobile Safari.Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio: 0) {.toggle-all,.todo-list li .toggle {background: none;}.todo-list li .toggle {height: 40px;}
}@media (max-width: 430px) {.footer {height: 50px;}.filters {bottom: 10px;}
}</style>

三.非父子通信(拓展)

(1) event bus 事件总线

作用:非父子组件之间,进行简易消息传递。(复杂场景 → Vuex)
1.创建一个都能访问到的事件总线(空Vue实例) → utils / EventBus . js

import Vue from 'vue'const Bus  =  new Vue()export default Bus

2.A组件(接收方),监听Bus实例的事件

created() {Bus.$on('sendMsg', (msg) => {// console.log(msg)this.msg = msg})}

3.B组件(发送方),触发Bus实例的事件

Bus.$emit('sendMsg', '今天天气不错,适合旅游')

(2)provide & inject:跨层级共享数据

1.父组件provide提供数据

export default {provide() {return {// 简单类型 是非响应式的color: this.color,// 复杂类型 是响应式的userInfo: this.userInfo,}},

2.子 / 孙组件inject取值使用

export default {inject: ['color', 'userInfo'],
}

四.v-model

(1)原理:v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写

作用:提供数据的双向绑定
①数据变,视图跟着变:value
②视图变,数据跟着变@input
注意:$event用于在模板中,获取时间的形象

<template><div class="app"><input type="text" v-model="msg1" /><br /><!-- v-model的底层其实就是:value和 @input的简写 --><input type="text" :value="msg2" @input="msg2 = $event.target.value" /></div>
</template>
<script>
export default {data() {return {msg1: '',msg2: '',}},
}
</script>

(2)表单类组件封装 & v-model简化代码

1.表单类组件封装 → 实现子组件和父组件数据的双向绑定
①父传子:数据应该是负组件props传递过来的,v-model拆解绑定数据
②子传父:监听输入,子传父传值给父组件修改
父组件:

<BaseSelect :cityId="selectId" @事件名="selectId=$event"></BaseSelect>

子组件:

<select :value="value" @change="selectCity">
props: {value: String,},
methods: {selectCity(e) {this.$emit('input', e.target.value)},},

2.父组件v-model简化代码,实线子组件和父组件数据的双向绑定
①子组件中:props通过value接收,事件触发input
②父组件中:v-model给组件直接绑数据(:value + @input )
父组件:

<BaseSelect :value="selectId" @input="selectId=$event"></BaseSelect>

子组件:

<select :value="value" @change="handleChange">
props: {value: String,},
methods: {handleChange(e) {this.$emit('input', e.target.value)},},

五.sync修饰符

作用:可以实现子组件与父组件数据的双向绑定,简化代码
特点:prop属性名,可以自定义,非固定为value
场景:封装弹框类的基础组件,visible属性true显示false隐藏

<!-- isShow.sync  => :isShow="isShow" @update:isShow="isShow=$event" --><BaseDialog :isShow.sync="isShow"></BaseDialog>
 props: {isShow: Boolean,},methods:{closeDialog(){this.$emit('update:isShow',false)}

六.ref 和 $refs

作用:利用ref和$refs可以用于获取dom元素或组件实例
特点:查找范围 → 当前组件内(更精准稳定)
①获取dom
1.目标标签 - 添加ref属性

<div ref="ChartRef">子组件</div>

2.恰当时机,通过this . $refs . xxx,获取目标标签

mounted() {// 基于准备好的dom,初始化echarts实例// document.querySelector 会查找项目中所有的元素// $refs只会在当前组件查找盒子// var myChart = echarts.init(document.querySelector('.base-chart-box'))var myChart = echarts.init(this.$refs.baseChartBox)// 绘制图表}

②获取组件
1.目标标签 - 添加ref属性

<BaseForm ref="baseForm">子组件</BaseForm>

2.恰当时机,通过this . $refs . xxx,获取目标标签,就可以调用组件对象里面的方法

this.$refs.baseForm.组件方法()

七.Vue异步更新、$nextTick

1.点击编辑,显示编辑框
2.让编辑框,立即获取焦点


http://www.ppmy.cn/server/166018.html

相关文章

深度学习与搜索引擎优化的结合:DeepSeek的创新与探索

目录 引言 1. 传统搜索引擎的局限性 2. 深度学习在搜索引擎中的作用 3. DeepSeek 实现搜索引擎优化的关键技术 3.1 神经网络与搜索引擎优化 3.2 自然语言处理与查询理解 3.3 深度强化学习与搜索结果排序 4. DeepSeek的深度学习架构 4.1 查询解析与语义理解 4.2 搜索排名与相…

【数据安全】现代智能手机的数据加密机制

这两天刷抖音看到一个降智视频&#xff0c;说手机拿去修了明明没给他密码&#xff0c;但是他是怎么导出手机的数据呢&#xff0c;而且很多人看你都会有这样的疑问&#xff1a;“我的手机设有锁屏密码数据真的安全吗&#xff1f;锁屏密码存在意义是不是仅限于防止别人进入桌面这…

业务架构、数据架构、应用架构和技术架构

TOGAF(The Open Group Architecture Framework)是一个广泛应用的企业架构框架&#xff0c;旨在帮助组织高效地进行架构设计和管理。 TOGAF 的核心就是由我们熟知的四大架构领域组成:业务架构、数据架构、应用架构和技术架构。 企业数字化架构设计中的最常见要素是4A 架构。 4…

四、GPIO中断实现按键功能

4.1 GPIO简介 输入输出&#xff08;I/O&#xff09;是一个非常重要的概念。I/O泛指所有类型的输入输出端口&#xff0c;包括单向的端口如逻辑门电路的输入输出管脚和双向的GPIO端口。而GPIO&#xff08;General-Purpose Input/Output&#xff09;则是一个常见的术语&#xff0c…

深入理解k8s中的容器存储接口(CSI)

CSI出现的原因 K8s原生支持一些存储类型的PV&#xff0c;像iSCSI、NFS等。但这种方式让K8s代码与三方存储厂商代码紧密相连&#xff0c;带来不少麻烦。比如更改存储代码就得更新K8s组件&#xff0c;成本高&#xff1b;存储代码的bug还会影响K8s稳定性&#xff1b;K8s社区维护和…

FPGA的IP核接口引脚含义-快解

疑问 手册繁琐&#xff0c;怎样快速了解IP核各输入输出接口引脚的含义。 答疑 不慌不慌&#xff0c;手册确实比较详细但繁琐&#xff0c;如何快速知晓该部分信息&#xff0c;涛tao道长给你们说&#xff0c;简单得很&#xff0c;一般新入门的道友有所不知&#xff0c;往往后面…

机器学习 - 需要了解的条件概率、高斯分布、似然函数

似然函数是连接数据与参数的桥梁&#xff0c;通过“数据反推参数”的逆向思维&#xff0c;成为统计推断的核心工具。理解它的关键在于区分“参数固定时数据的概率”与“数据固定时参数的合理性”&#xff0c;这种视角转换是掌握现代统计学和机器学习的基础。 一、在学习似然函…

C++开发(软件开发)常见面试题

目录 1、C里指针和数组的区别 2、C中空指针请使用nullptr不要使用NULL 3、http/https区别和头部结构&#xff1f; 4、有了mac地址为什么还要ip地址&#xff1f;ip地址的作用 5、有了路由器为什么还要交换机&#xff1f; 6、面向对象三大特性 7、友元函数 8、大端小端 …