荐 Vue基础学习
vue基础
1.vue-介绍
Vue.js (view)是一套构建用户界面的前端框架技术(渐进式框架)。
内部集成了许多基础技术,例如html、css、javascript、ajax、node等,
当然还有vue本身高级技术体现,例如组件、过滤器、指令、路由、webpack等等.
2012年由中国人尤雨溪开发,正式发布于2014年2月 ,2016年3月加入阿里巴巴公司(该事件助推了vue的发展)
jquery与vue的区别:
jquery:库 侵入性弱 (工具 库),项目 对其进行 安装卸载 非常方便
vue:框架 侵入性强 (框架),项目 从内到外 都是vue,不可以随便拆卸
Vue只关注视图(页面)层的开发,文档非常丰富、易于上手,流行度高,拥抱经典的web技术、早期灵感来源于angular
vue.js兼具angular.js和react.js的优点,并剔除了它们的缺点
支持所有兼容ECMAScript 5的浏览器,IE9以上,Vue.js 不支持 IE8 及其以下版本
vue是前端的主流框架之一,和Angular、React 一起,并成为前端三大主流框架!
2.MVVM设计模式
m: model 数据部分 data
v:view 视图部分 div容器
vm: view & model 视图和数据 的 结合体
3.vue基本使用
<!-- 2. 创建一个供vue操控的 标签容器(推荐是div) -->
<div id="app">
<!-- 输出vue实例的data数据,在HTML中使用data里面的数据不需要加this -->
{{ city }}--------{{ weather }}
</div>
<!-- 1.引入vue文件包,此时系统增加了一个全局变量为Vue-->
<script src="./vue.js"></script>
<script>
// 3. 实例化Vue对象
var vm = new Vue({
// el:'选择器' ,// el固定名称,理解为element,使得 Vue实例 与 标签容器 联系
el:'#app',
// data固定名称,给 Vue实例 声明数据,用于使用
data:{
city:'北京',
weather:'sunshine'
}
})
</script>
4.插值表达式{{}}
<标签> {{ 表达式 }} </标签>
表达式:变量、常量、算术运算符、比较运算符、逻辑运算符、三元运算符等等
如果{{}}使用中有冲突,想更换为其他标记,可以这样:
var vm = new Vue({
//delimiters:['${','}$'], // 标记符号变为${ }$
delimiters:['#{','}#'], // 标记符号变为#{ }#
})
插值表达式只能用在html标签的内容区域;不能用在其他地方
插值表达式使用时,页面加载时出现会闪烁问题
解决方法:v-cloak
<style type="text/css">
/* 通过属性选择器 选择到 带有属性 v-cloak的标签 让他隐藏*/
[v-cloak]{
/* 元素隐藏 */
display: none;
}
</style>
<div id="app">
<!-- 2、 让带有插值表达式语法的 添加 v-cloak 属性
在 数据渲染完成之后,v-cloak 属性会被自动去除,
v-cloak一旦移除也就是没有这个属性了 属性选择器就选择不到该标签
也就是对应的标签会变为可见
-->
<div v-cloak >{{msg}}</div>
</div>
5.v-text
v-text与{{}}的作用是一样的,都是操控标签的内容区域信息
<标签 v-text="表达式"> </标签>
v-text 是通过标签的属性形式呈现
如果 标签 内容区域 有默认信息,则会被v-text覆盖掉
v-text 可以进行 变量、常量、算术符号、比较符号、逻辑符号、三元运算符号等运算
6.v-html
v-html 与 v-text、{{ }} 的作用一样,都是操控 标签的内容区域
<标签 v-html="表达式"> </标签>
v-html、v-text、{{ }}的异同:
- v-html对 html标签 和 普通文本 内容都可以设置显示
- v-text、{{ }} 只针对 字符串 起作用,如果数据中有html标签,那么标签的箭头符号要做字符实体转换,进而使得浏览器上直接"显示箭头"等标签内容,等同于不解析html标签内容
- < 变为 < // less than
- > 变为 > // great than
- v-html和v-text没有加载闪烁问题
- 它们都可以进行 变量、常量、算术运算、比较运算、逻辑运算、三元运算等技术应用
应用场景
如果服务器返回的数据中,包含有HTML标签(例如富文本编辑器内容),可以使用 v-html 来渲染,(v-text和 {{}}都不行)
默认内容
<p>{{score}}默认内容</p>
<p v-text="score">默认内容</p>
<p v-html="score">默认内容</p>
以上三者,v-text和v-html标签有默认内容,但是都会被覆盖掉,而 插值表达式 不会覆盖
注意:
- v-html尽量避免使用(除非完全掌控),否则会带来危险(XSS攻击 跨站脚本攻击)
- 标签的默认内容会被v-html覆盖
7.属性绑定v-bind(冒号:)
7.1属性绑定-基本使用
使用 v-bind指令 对标签属性进行绑定
<标签 v-bind:属性名称="表达式" ></标签>
<标签 :属性名称="表达式"></标签> <!--简易方式设置,推荐使用-->
如果有需要,绑定的内容可以进行 变量、常量、算术运算、比较运算、逻辑运算、三元运算等技术应用
通过v-bind对img标签的src、width、height属性进行绑定
<div id="app">
<p>
<img v-bind:src="mysrc" alt="" :width="wh" :height="ht" />
</p>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
mysrc:'./laofu.jpg',
wh:280,
ht:190
}
})
</script>
7.2属性绑定-class属性
使用 v-bind 对标签的class属性进行绑定
class属性较比其他属性不一样的地方是,其既可以接收一个值,也可以通过空格分隔接收多个值
<tag class="apple"></tag> <!--接收一个值-->
<tag class="apple pear orange"></tag> <!--接收多个值-->
class属性绑定的语法:
1) 对象方式
<tag :class="{xx:true, xx:false}"></tag>
<!--true: 设置 false:不设置-->
2) 数组方式
<tag :class="['xx','yy','zz']"></tag>
<!--数组元素值如果不是vue的data成员 就要通过单引号圈选,代表是普通字符串-->
<style>
.apple{color:blue;}
.pear{font-size:25px;}
.orange{background-color:hotpink;}
</style>
<div id="app">
<h2>属性绑定</h2>
<!-- <p class="apple pear orange">学习Vue课程</p> -->
<!-- 通过vue方式给class绑定如上3个信息 -->
<!-- 1. 对象方式 -->
<p :class=" {apple:true, pear:true, orange:true, banana:false} ">学习Vue课程</p>
<!-- 2. 数组方式 -->
<p :class=" ['apple','pear','orange'] ">学习Vue课程</p>
</div>
7.3属性绑定-style属性
使用v-bind指令操控style属性
style样式属性较比普通属性也比较特殊,其也可以接收多个值
<p style="color:red; font-size:25px; background-color:lightgreen;"></p>
style属性绑定语法:
1) 对象方式
<tag :style="{xx:yy,xx:yy.....}"></tag>
<!--xx:样式名称,yy:样式的值-->
2) 数组方式
<tag :style="[{xx:yy},{xx:yy.....}]"></tag>
<!--根据需要,数组的每个元素都是一个对象,每个对象包含一对或多对css样式-->
<p style="color:blue;font-size:25px;background-color:hotpink;">学习Vue课程-style绑定</p>
<div id="app">
<h2>属性绑定</h2>
<!-- 通过vue实现给style绑定多个css样式信息 -->
<!-- 1. 对象方式 -->
<p :style=" {'color':'blue','fontSize':'25px','background-color':'hotpink'} ">学习Vue课程-style绑定</p>
<!-- 2. 数组方式 -->
<p :style=" [{'color':'blue','fontSize':'25px','background-color':'hotpink'}] ">学习Vue课程-style绑定</p>
<p :style=" [{'color':'blue'},{'fontSize':'25px','background-color':'hotpink'}] ">学习Vue课程-style绑定</p>
<p :style=" [{'color':'blue'},{'fontSize':'25px'},{'background-color':'hotpink'}] ">学习Vue课程-style绑定</p>
</div>
- 数组方式绑定style属性,每个数组元素可以包含一个或多个css样式对象
- 复合属性带中横线(例如background-color)的需要通过单引号圈选,或变为驼峰命名
通过传统方式也可以操作class或style属性,但是Vue的操控会更加灵活 和 精准,可以针对某一个值进行设置
8.事件绑定v-on(@)
8.1事件绑定-基本使用
使用v-on给标签绑定事件
web端网页应用程序开发,事件是一个不可或缺的技术
在vue中给元素进行事件绑定,需要通过v-on:指令实现,或使用@符号,@是v-on:的简写,使用更方便
事件类型:
鼠标事件:click dblclick mouseenter mouseleave mouseover mousedown等等
键盘事件:keyup keydown keypress 等等
注意:
- 事件处理驱动 需要通过methods定义
- 被绑定的事件类型可以是 click、dblclick、keyup、keydown等等,不需要设置on标
<div id="app">
<h2>事件操控</h2>
<!--@是 v-on: 的简写,推荐使用,记住-->
<button v-on:click="say()">说</button>
<button @click="say()">说</button>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
},
// 给Vue实例 声明方法,该方法可以给事件使用
methods:{
say(){
console.log('hello,北京')
}
}
})
</script>
8.2事件绑定-传递参数
vue“单击”事件参数的3种类型:
- 有声明(),也有传递实参,形参就代表被传递的实参
- 有声明(),但是没有传递实参,形参就是undefined
- 没有声明(),第一个形参就是事件对象 [object MouseEvent/鼠标事件对象]
8.3事件绑定-访问data成员
根据业务需要,事件在执行过程中需要对Vue实例的data数据进行操作,通过this关键字实现
this代表Vue实例对象,并且针对data或methods成员都可以直接进行调用
8.4事件绑定-this是谁
在Vue实例内部包括不限于methods方法中,this关键字 是Vue实例化对象,具体与 new Vue() 是一样的
并且其可以对 data 和 methods成员进行直接访问
可以理解为this和vm是同一个对象的两个不同名字,this === vm
8.5事件绑定-方法简易设置
根据es6标准,可以给methods各个成员方法做简易设置如下:
方法名称:function(){} 简易设置为: 方法名称(){}
9.this指向
-
普通函数调用,this就是window对象
var age = 20 function getInfo(){ console.log(this) // window console.log(this.age) } getInfo() // 20
-
作为对象的方法调用,this代表调用该方法的当前对象
const tiger = { name:'东北虎', act:'猛虎扑食', say(){ console.log('我的名字是'+this.name+',我的招牌动作是'+this.act) // this代表tiger对象 } } tiger.say()
-
this代表元素节点对象
<button onclick="this.style.color='red'" />确定</button>
注意:this在不同情况下代表不同对象,不用强记,通过console.log输出查看便知
10.双向数据绑定v-model
v-model,其被称为双向数据绑定指令,就是Vue实例对数据进行修改,页面会立即感知,相反,页面对数据进行修改,Vue内部也会立即感知.
v-model是vue中 唯一实现双向数据绑定指令
v-bind(单向)数据绑定,Vue实例修改数据,页面会感知到,相反页面修改数据Vue实例不能感知
v-model(双向)数据绑定,页面修改数据,Vue实例会感知到,Vue实例修改数据,页面也会感知到
10.1基本使用
<标签 v-model="data成员"></标签>
注意:
- v-model只针对value属性可以绑定,因此经常用在form表单标签中,例如input(输入框、单选按钮、复选框)/select(下拉列表)/textarea(文本域),相反div、p标签不能用
- v-model只能绑定data成员,不能设置其他表达式,否则错误
- v-model绑定的成员需提前在data中声明好
<div id="app">
<p>{{ city }}</p>
<p><input type="text" :value="city"></p>
<p><input type="text" v-model="city"></p>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
city:'北京'
},
})
</script>
v-model对应的city发生变化后,其他的{{ }} 和 :value的值也会发生变化
10.2响应式
v-model数据双向绑定步骤:
- 页面初始加载,vue的data数据渲染给div容器
- 通过v-model修改数据,修改的信息会直接反馈给vue内部的data数据
- vue的data数据发生变化,页面上(也包括Vue实例本身)用到该数据的地方会重新编译渲染。
- 2和3 步骤在条件满足情况下会重复执行
响应式:
vue实例的data数据如果发生变化,那么页面上(或Vue实例内部其他场合)用到该数据的地方会重新编译执行,这样就把更新后的内容显示出来了,这个过程就是“响应式”,即上面步骤3
- 如果Vue实例内部对变化的数据有使用,也会同步更新编译执行
注意:响应式 是Vue中非常重要的机制
10.3v-model实现原理
给input输入框中定义oninput事件,在该事件中把用户输入的信息都给随时获得到,并对data成员进行赋值
data成员变化了,页面上用到数据的地方就重新渲染,达成简易双向绑定的效果
<div id="app">
<h2>v-model简易原理</h2>
<p>{{city}}</p>
<p><input type="text" :value="city" @input="city = $event.target.value"></p>
<p><input type="text" :value="city" @input="feel"></p>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
city:'北京'
},
// 给Vue实例 声明方法,该方法可以给事件使用
methods:{
feel(evt){
this.city = evt.target.value
}
}
})
</script>
oninput:是一个键盘事件,可以随时感知输入框输入的信息
$event:在vue的事件被绑定元素的行内部,代表事件对象
event.target: 触发当前事件的元素节点dom对象
注意:
- 事件声明没有小括号(),第一个形参就是 事件对象
- 在元素行内事件驱动中可以直接使用**$event**,其也是事件对象
11.遍历v-for
使用v-for指令,遍历数组信息
<标签 v-for="成员值 in 数组"></标签>
<标签 v-for="(成员值,下标) in 数组"></标签>
<div id="app">
<ul>
<li v-for="item in color" :key="item.id">{{item}}</li>
</ul>
<ul>
<li v-for="(item,k) in color" :key="item.id">{{k}}-----{{item}}</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
color:['red','yellow','pink']
},
methods:{
}
})
</script>
注意:使用v-for指令的html标签,由于遍历机制,本身标签会被创建多份出来
在vue中v-for做遍历应用时,都需要与**:key**一并进行使用
在2.2.0+版本里边,v-for使用的同时必须使用:key,以便vue能准确跟踪每个节点,从而重用和重新排序现有元素,需要为每个数据项提供一个唯一的、代表当前项目的属性值赋予给key
<tr v-for="(item,k) in brandsList" :key="item.id">
注意:
- :key不设置,也是存在的,默认绑定每个项目下标序号信息
- key是一个普通属性,前边设置**:冒号**,代表属性绑定
12. v-if 和 v-show
在vue中,v-if 和 v-show 会根据接收 true/false 信息使得页面上元素达到显示或隐藏的效果
<标签 v-if="true/false"></标签>
<标签 v-show="true/false"></标签>
<!--true:显示 false:隐藏-->
原理:
v-if:通过 创建、销毁dom的 方式达到显示、隐藏效果的(销毁后有一个占位符)
v-show:其是通过css样式控制达成显示、隐藏效果的
-
display:none; 隐藏
-
display:block; 显示
特点:
v-if 有更高的切换消耗 、v-show有更高的渲染消耗
如果需要频繁切换 则v-show 较合适,如果运行条件不大,可能改变 则v-if 较合适。
注意:
v-if使得元素被隐藏后,这个元素的物理位置有一个名称为""的占位符,其与html的注释信息没有关系
简单案例:通过按钮控制,使得元素内容在 显示 和 隐藏 之间切换
<div id="app">
<h2>v-if和v-show</h2>
<button @click="flag=!flag">切换</button>
<p id="one" v-if="flag">学习vue第二天---v-if</p>
<p id="two" v-show="flag">学习vue第二天---v-show</p>
</div>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
flag:false // 控制标签是否显示true/false
},
});
</script>
注意:事件驱动不仅可以是methods方法,也可以是简单的js语句
13. v-if 和 v-else
在Vue中,v-if 、v-else-if 和 v-else 三个指令结合可以实现多路分支结构
- v-if可以单独使用,形成单路分支结构
- v-if 和 v-else 也可以合作使用,实现双路分支结构
- v-if 、v-else-if 和 v-else 也可以合作使用,实现多路分支结构
<标签 v-if="true/false"></标签>
<标签 v-else-if="true/false"></标签>
<标签 v-else-if="true/false"></标签>
<标签 v-else></标签>
以上4个标签分支结构,最终只会走一个,第一个为true的那个标签会执行 或 执行v-else
判断信息是否存在,并显示对应内容
<table v-if="brandList.length>0">
……
</table>
<table v-else>
<tr><td>没有任何记录!</td></tr>
</table>
注意:v-if和v-else一并使用,页面没有占位符了
14.vue生命周期
生命周期是指vue实例(或者组件)从诞生到消亡所经历的各个阶段的总和
- 创建阶段:由空白期、data/methods初始化、模板挂载、模板渲染等组成
- 运行阶段:分为 更新前 和 更新后 两部分
- 销毁阶段:分为 销毁前 和 销毁后
成员方法:
各个阶段在Vue实例内部都有对应的成员方法,可以定义、执行、感知
创建:beforeCreate created beforeMount mounted
运行:beforeUpdate updated
销毁: beforeDestroy destroyed
不同阶段完成不同的任务,开发者可以利用各个阶段的特点完成业务需要的相关功能
14.1创建阶段
创建阶段一共有4个方法,它们与 el、data都是并列关系的,重点记住created()方法
new Vue({
beforeCreate(){ }, //Vue实例已经创建完毕,但是相关的成员都没有
created(){ }, //此时data 和 methods已经准备好了,但是还没有去找div容器
//可以用于页面首屏数据获取操作,获取回来的数据存储给data的某个成员
beforeMount(){ }, //Vue实例获取到div容器,但是div容器的内容还是没有编译前的原生内容
mounted(){ }, //Vue实例已经完成了div容器内容的编译,并把编译好的内容渲染给div容器
})
beforeCreate:此时Vue对象刚创建好,没有任何成员,data、methods等都没有,只有this
created:此时vue对象内部已经完成了data、methods等成员的设置,也是data初始化的最好时机
beforeMount:此时vue实例已经把div容器给获得到了,但是内部的vue指令等信息还没有被编译处理
mounted:此时,vue获取到的div容器内部的原生指令已经被编译处理好了,并且也完成了容器的渲染工作,此时模板中已经看不到vue原始指令了
重点关注 created :
created: 一般用于页面"首屏"数据的获取操作(获取好的数据可以直接赋予给data使用,此方法已经把data做好了,其可以做到第1 时间就把数据赋予给data,供后续使用)
注意:创建阶段各个方法不设置则以,设置后就会自动执行,并且会顺序只执行一次
14.2运行阶段
运行阶段:
new Vue({
beforeUpdate(){ 可以感知到data数据变化之前页面上关于该数据的样子 }
updated(){ 可以感知到data数据变化之后页面上该数据的样子 }
})
运行阶段方法不会自动执行,当data成员数据发生变化,才会执行,并且数据变化多次,方法也会重复执行多次
14.3销毁阶段
销毁阶段:
new Vue({
beforeDestroy(){ vue实例销毁之前 }
destroyed(){ vue实例销毁之后 }
})
当vue实例被销毁后,就会执行以上两个方法,只有调用vm.$destroy()可以销毁vue实例
生命周期的各个方法与 el、data、methods 等成员都是并列的,它们有固定的执行顺序,与设置顺序没有关系
15.按键修饰符
按键修饰符
:
使得键盘事件只针对某个(或某几个)按键生效
应用中有许多 键盘事件 (onkeyup、onkeydown、onkeypress、oninput等等),每个事件在执行的时候可以通过许多键子达成,有时我们要求只有按到某个键子时,才激活该事件,例如只有触碰 回车键或ESC键 才有效果,那么可以通过 按键修饰符 实现
oninput: 触碰键盘给输入框做输入动作时会触发执行
onkeyup: 键盘抬起触发执行
onkeypress:按下任何字母数字键时触发执行,系统按钮(例如,箭头键和功能键)无法得到识别
onkeydown:按下任何键盘键(包括系统按钮,如箭头键和功能键)时触发执行
键码值
:
键盘每个按键都对应一个数字码,称为 键码值
全部按键键码值: https://blog.csdn.net/qq_39207948/article/details/79882229
常用控制键键码值:
按键 | 键码 | 按键 | 键码 |
---|---|---|---|
Tab | 9 | Left Arrow | 37 |
Enter | 13 | Up Arrow | 38 |
Shift | 16 | Right Arrow | 39 |
Control | 17 | Dw Arrow | 40 |
Alt | 18 | Esc | 27 |
Delete | 46 |
语法
:
<input @keyup.键码值/别名="处理事件">
<!--要求只有触碰回车键 才执行该事件-->
<input @keyup.13="处理事件"> <!--键码值-->
<input @keyup.enter="处理事件"> <!--别名-->
<!--键码值:键盘的每个键子都有一个数字码,就是键码值,event.keyCode 就获取到了-->
键码值别名
:
vue考虑到键码值使用多有不便,已经给常用键码值(event.keyCode)设置别名
按键 | 别名 |
---|---|
Tab | .tab |
Enter | .enter |
Delete |
.delete (捕获“删除”和“退格”按键) |
Esc | .esc |
Up Arrow | .up |
Dw Arrow | .down |
Left Arrow | .left |
Right Arrow | .right |
Space | .space |
自定义按键别名
:
// 要求使用 `@keyup.f6`
Vue.config.keyCodes.f6 = 118
<input @keyup.f6="xxx" /> // 只有单击f6键才会触发xxx的回调
注意
:
- 如果有的需求比较特殊,需要多个按键一并触发该事件,也可以
@keyup.ctrl.enter="XXX"
表示 ctrl和enter一并触碰,才触发事件执行
案例应用
:
给添加信息的输入框设置 按键修饰符
- 回车键 被触碰就添加新的信息
- ESC键 被触碰就把已经输入的信息做清除操作,取消添加
<input type="text" v-model="newInfo" @keyup.enter="add" @keyup.esc="newInfo=''"/>
上述案例中,一个input输入框设置了两个keyup事件,是可以的,它们是通过不同的键触发的
16.自定义指令directive
自定义指令
:
Vue框架给我们提供了许多指令,例如v-if 、v-else、 v-html、v-show、v-text、v-model、v-bind等等,这些指令都是固定的,并不能任意满足我们,有时需要一个指令而框架没有提供,就需要我们自定义,称为“自定义指令”
关键字:directive directives
16.1私有自定义指令
声明语法
:
// 声明私有指令
new Vue({
directives:{
指令名称:{ 配置对象成员 }
}
})
// 配置对象:
inserted(m){
m:代表使用该指令的html标签dom对象,可以通过m进行原始dom操作实现业务需求
}
注意
:私有指令directives关键字 与el、data等都是并列的
案例应用
创建一个私有自定义指令,使得在页面加载完毕后 ”输入框“ 自动获得焦点
创建指令:
// 注册自定义指令
directives:{
// 指令名称注册时不要设置"v-",使用时再设置
'dian':{
// inserted是固定用法
// inserted:时机的事情,代表是div容器被Vue实例编译完毕,并且也渲染好了
inserted:function(m){
// m:代表使用该指令的元素dom对象
// dom对象可以通过webapi技术操作页面元素
// m.style.color = 'red'
m.focus() // 使得input框元素获得焦点
}
}
},
应用指令:
<input type="text" v-dian v-model="newbrand" " />
注意
:无论是全局指令 还是 私有指令,声明的时候都不用设置v-前缀,使用的时候再添加上即可
16.2全局自定义指令
声明语法
:
// 声明全局指令
Vue.directive(指令名称,{ 配置对象成员 })
// 配置对象:
inserted(m){
m:代表使用该指令的html标签dom对象,可以通过m进行原始dom操作实现业务需求
}
案例应用
创建一个全局自定义指令,使得页面加载完毕后 ”输入框“ 自动获得焦点
创建指令:
Vue.directive('dian2',{
inserted(m){
// m:代表使用指令的html对象(dom对象)
// 使得m对象获得焦点
m.focus()
}
})
var vm = new Vue()
应用:
<input type="text" v-dian2 v-model="newbrand" @keyup.enter="add" @keyup.esc="newbrand=''" />
17.VirtualDOM
VirtualDOM
:
div容器 在 Vue实例中存在的状态,就是 VirtualDOM(虚拟dom内容),具体是内存信息的体现
在Vue实例运行期间,该VirtualDOM始终存在
VirtualDOM作用
:
- 编译解析div容器,并渲染给浏览器
- 响应式体现
本文地址:https://blog.csdn.net/jyn15159/article/details/107248354