前端框架学习
(一)Vue实现
1.1 简介
-
Vue 是一套用于构建用户界面的渐进式 JavaScript框架。
-
渐进式框架:表示我们可以在项目中一点点来引入和使用Vue,而不一定需要全部使用Vue来开发整个项目
-
vue的两个特性:
- 声明式渲染:Vue 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。
- 响应性:Vue 会自动跟踪 JavaScript 状态并在其发生变化时响应式地更新 DOM。
-
第一个vue程序:
-
步骤:
-
1.导入开发版本的vue.js
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
-
2.创建vue实例对象,设置el属性和data属性。
-
使用简洁的模板语法把数据渲染到页面上
<body> <div id="app"> {{message}} </div> <script> new Vue({ el: '#app', data: { message: "hello world" } }) </script> </body>
-
-
1.2 引入vue的方式:
1.2.1 CDN引入
在页面中通过CDN的方式来引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
1.2.2 手动引入
下载Vue的JavaScript文件,并且自己手动引入
<script src="../js/vue.js"></script>
1.2.3 npm包管理安装使用
通过npm包管理工具安装使用它
1.2.4 Vue CLI创建项目使用
直接通过Vue CLI创建项目,并且使用它;
1.3 基础语法
1.3.1 模板语法
-
概念:Vue模板语法是一种声明式的标记语言,用于将组件的数据渲染进DOM。
-
Vue的响应式系统是Vue框架的核心特性之一。当使用Vue模板语法绑定数据时,Vue会自动追踪依赖,并在数据变化时更新DOM。
-
基础语法详解:
-
插值表达式
-
插值表达式是Vue模板中最基本的数据绑定方式。它允许将JavaScript表达式的值嵌入到模板中
<!-- 基本文本插值 --> <span>Message: {{ message }}</span> <!-- 表达式插值 --> <span>Count: {{ count + 1 }}</span>
-
-
指令
- 指令是Vue模板中的特殊标记,用于告诉Vue应该如何响应数据的变化。
-
1.3.2 el挂载点
- el是用来设置Vue实例挂载(管理的元素)
- Vue会管理el选项命中的元素及内部的后代元素
- 可以使用其他选择器,但建议使用id选择器
可以使用其他的双标签,但不建议使用html和body标签
1.3.3 data数据对象
-
vue中用到的数据定义在data中
-
data可以写复杂数据,渲染复杂数据时,遵守js语法就可以了
<div id="app">
<!-- {{message}} -->
这是介绍:{{school.name+"在"+school.add+" 校区分布在"+campus[0]+campus[1]+campus[2]}}
<!-- 这是介绍:黑马程序员在湖南长沙 校区分布在北京校区上海校区长沙校区 -->
</div>
<script>
new Vue({
el: '#app',
data: {
message: "hello world",//字符串
school: {
name: '黑马程序员',
add: '湖南长沙'
},
campus: ["北京校区", "上海校区", "长沙校区"]
}
})
</script>
1.3.4 vue-本地应用(vue指令)
指令:带有v-前缀的特殊标签属性
(1)内容绑定、事件绑定(v-text、v-html、v-on)
-
v-text 设置标签文本值:v-text 可以将 data 中的数据通过 {{}} 插值表达式 设置到 html 标签的内容中,并且默认是替换标签内的全部内容。另外, v-text 中也支持写表达式,例如通过 “+” 进行字符串或 data 的拼接.
<span v-text="message+school.name">你好</span>
-
v-html 设置标签的 innerHTML:v-html指令可以将内容中的 html 解析成标签,而 v-text 只能解析成文本.
<div v-html="htmlStr"></div> <div v-text="htmlStr"></div> <!-- 百度 <a href="https://www.baidu.com">百度</a> -->
-
v-on 为元素绑定事件
v-on 指令就是为元素绑定事件的(注册事件),也可以将 v-on 简写为 @. 绑定的方法定义在 methods 属性中,方法内部必须通过 this 关键字访问到定义在 data 中的数据.
v-on:click="方法":点击事件. v-on:dblclick="方法":双击事件. v-on:monseenter="方法":鼠标移入事件.
语法:
(1)v-on:“事件名”=“内联语句”
<div id="count"> <button v-on:mouseenter="count--">-</button> <span>{{count}}</span> <button @mouseenter="count++">+</button> </div> <script> new Vue({ el: "#count", data: { count: 100 } }) </script>
(2)v-on:“事件”=“methods中的函数名”.
在methods中是等同的。
fn(){}, fn:function(){}
<div id="app"> <button type="button" @click="counter">计数器+1</button> <button type="button" v-on:click="counter">计数器+1</button> <div>计数器的数量为{{count}}</div> </div> <script> new Vue({ el: "#app", data: { count: 0, }, methods: { counter: function () { this.count += 1; } } </script>
(2)显示切换、属性绑定(v-show、v-if 、v-bind )
-
v-show
- 作用: 控制元素显示隐藏
- 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
- 原理: 切换 display:none 控制显示隐藏
- 场景:频繁切换显示隐藏的场景
-
v-if
-
作用: 控制元素显示隐藏(条件渲染)
-
语法: v-if= “表达式” 表达式值 true显示, false 隐藏
-
原理: 基于条件判断,是否创建 或 移除元素节点
-
场景: 要么显示,要么隐藏,不频繁切换的场景
-
v-else 和 v-else-if
-
作用:辅助v-if进行判断渲染
-
语法:v-else v-else-if=“表达式”
-
需要紧接着v-if使用
<body> <div id="app"> <p v-if="gender">性别:♂ 男</p> <p v-else>性别:♀ 女</p> <hr> <p v-if="score>=90">成绩评定A:奖励电脑一台</p> <p v-else-if="score>=80">成绩评定B:奖励周末郊游</p> <p v-else-if="score>=70">成绩评定C:奖励零食礼包</p> <p v-else>成绩评定D:惩罚一周不能玩手机</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { gender: 2, score: 95 } }) </script> </body>
-
-
-
v-bind
- **作用:**动态设置html的标签属性 比如:src、url、title
- 语法:**v-bind:**属性名=“表达式”
- **v-bind:**可以简写成 => :
比如,有一个图片,它的
src
属性值,是一个图片地址。这个地址在数据 data 中存储。则可以这样设置属性值:
<img v-bind:src="url" />
<img :src="url" />
(v-bind可以省略)
(3)列表循环、表单元素绑定(v-for 、v-model )
-
v-for:Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
- v-for 指令需要使用
(item, index) in arr
形式的特殊语法,其中:- item 是数组中的每一项
- index 是每一项的索引,不需要可以省略
- arr 是被遍历的数组
此语法也可以遍历对象和数字
- v-for 指令需要使用
<div id="app">
<h2>我的水果店</h2>
<ul>
<li v-for="(item,index) in list">水果{{item}}在数组的第{{index}}索引上</li>
<!-- 如果用不上index 可以省略index 写成:item in list -->
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: ['苹果', '香蕉', '菠萝']
}
})
</script>
v-for中的key
//
语法:key属性=“唯一值”
作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用。
**为什么加key:**Vue 的默认行为会尝试原地修改元素(就地复用)
-
v-model
- 作用:给表单元素使用,双向数据绑定,可以快速获取或设置表单元素。
- 可以让数据和视图,形成双向数据绑定
- 数据变化,视图自动更新
- 视图变化,数据自动更新
作用: 给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
**语法:**v-model=“变量”
1.3.5 指令修饰符
所谓指令修饰符就是通过“.”指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码。
(1)按键修饰符
- @keyup.enter —>当点击enter键的时候才触发
<input type="text" placeholder="请输入任务" v-model="newItem" @keyup.enter="addTask">
//在键盘输入回车时,触发addTask
(2)v-model修饰符
-
v-model.trim —>去除首位空格
<input type="text" placeholder="请输入任务" v-model.trim="newItem" @keyup.enter="addTask">
-
v-model.number —>转数字
(3)事件修饰符
事件冒泡:当事件在DOM树中传播时,首先会在事件发生的元素(即事件的目标元素)上触发,然后逐级向上传播到DOM树的根节点(在HTML文档中通常是<html>元素),这个过程称为事件冒泡。
阻止冒泡:event.stopPropagation
默认行为:默认行为是指浏览器对特定事件做出的标准响应。例如,点击链接(<a>元素)的默认行为是导航到新页面,提交表单(<form>元素)的默认行为是将数据发送到服务器。
阻止默认行为:event.preventDefault()
-
阻止冒泡:@事件名.stop
<h3>阻止冒泡</h3> <div id="app"> <div class="father" @click="fatherFn">父亲 <div class="son" @click.stop="sonFn"> 儿子</div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> new Vue({ el: "#app", data: {}, methods: { fatherFn() { alert("父亲被点击了") }, sonFn() { alert("儿子被点击了") }, } })
-
事件名.prevent —>阻止默认行为
<a @click.prevent href="http://www.baidu.com">点击就会跳转</a>
-
事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
1.3.6 v-bind对样式控制的增强-操作class
为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制 。
(1)语法
<div> :class = "对象/数组">这是一个div</div>
(2)对象语法
当class动态绑定的是对象时,键就是类名,值就是布尔值,如果值是true,就有这个类,否则没有这个类
<div class="box" :class="{类名1:布尔值,类名2:布尔值}"></div>
适用场景:一个类名,来回切换
案例:tab导航高亮
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid red;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: black;
}
li a.active {
color: #fff;
background-color: #e01222;
}
</style>
</head>
<body>
<!-- 导航tab高亮 -->
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index">
<a :class="{active: index===activeIndex}" href="#">{{item.name}}</a>
</li>
</ul>
</div>
<!--
需求:基于数据动态渲染tab
准备下表记录高亮的是哪一个tab
基于下标,动态控制class类名
-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: [
{
id: 1, name: '京东秒杀'
},
{
id: 2, name: "每日特价"
},
{
id: 3, name: "品类秒杀"
}
],
activeIndex: 1
},
})
</script>
</body>
(3)数组对象
当class动态绑定的是数组时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
<div class="box" :class="[类名1, 类名2, 类名3 ]"></div>
使用场景:批量添加或删除类
案例:tab导航高亮
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid red;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: black;
}
li a.active {
color: #fff;
background-color: #e01222;
}
</style>
</head>
<body>
<!-- 导航tab高亮 -->
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index">
<a :class="{active: index===activeIndex}" href="#">{{item.name}}</a>
</li>
</ul>
</div>
<!--
需求:基于数据动态渲染tab
准备下表记录高亮的是哪一个tab
基于下标,动态控制class类名
-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: [
{
id: 1, name: '京东秒杀'
},
{
id: 2, name: "每日特价"
},
{
id: 3, name: "品类秒杀"
}
],
activeIndex: 1
},
})
</script>
</body>
1.3.7 v-bind对样式控制的增强-操作style
(1)语法
:style="样式对象"
<div class="box" :style="{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div>
注意:js里面不支持带-的属性写法:
<div id="app">
<div class="box" :style="{ width:'400px',height:'200px',backgroundColor:'green'}"></div>
</div>(要把background-color特殊属性用引号带起来)或者使用驼峰:
请注:里面的对象键值不要用双引号,一定要单引号
适用场景:某个具体属性的动态设置
(2)进度条案例
案例:进度条
<style>
.progress {
height: 25px;
width: 400px;
border-radius: 15px;
background-color: #272425;
border: 3px solid #272425;
box-sizing: border-box;
margin-bottom: 30px;
}
.inner {
width: 50%;
height: 20px;
border-radius: 10px;
text-align: right;
position: relative;
background-color: #409eff;
background-size: 20px 20px;
box-sizing: border-box;
transition: all 1s;
}
.inner span {
position: absolute;
right: -20px;
bottom: -25px;
}
</style>
<body>
<div id="app">
<div class="progress">
<div class="inner" :style="{width: percent+'%'}">
<span>{{percent}}%</span>
</div>
</div>
<button @click="percent=25">设置25%</button>
<button @click="percent=50">设置50%</button>
<button @click="percent=75">设置75%</button>
<button @click="percent=100">设置100%</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
percent: 0
}
})
</script>
1.3.8 v-model 应用于其他表单元素
前面演示的为input输入框,其他表单元素:
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素
输入框 input:text ——> value
文本域 textarea ——> value
复选框 input:checkbox ——> checked
单选框 input:radio ——> checked
下拉菜单 select ——> value
...
<body>
<div id="app">
<h3>小黑学习网</h3>
<label for="name">姓名</label>
<input type="text" id="name" v-model="username">
<br><br>
<label for="single">是否单身</label>
<input type="checkbox" id="single" v-model="isSingle">
<br><br>
<!-- <label for="sex">性别</label> -->
<!--
前置理解:
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 → v-model
-->
性别
<input v-model="gender" type="radio" name="gender" value="1">男
<input v-model="gender" type="radio" name="gender" value="2">女
<br><br>
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
-->
<label for="city">所在城市</label>
<select v-model="city" name="city" id="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="成都">成都</option>
<option value="南京">南京</option>
</select>
<br><br>
自我描述:
<br>
<textarea v-model="area"></textarea>
<button>立即注册</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
username: '杨淑琦',
isSingle: true,
gender: 2,//v-model会绑定到value里面
city: "成都",
area: "这是我的自我介绍"
}
})
</script>
1.3.9 计算属性
(1)概念语法:
-
概念:基于现有的数据,计算出来的新属性,依赖的数据变化,那么自动重新计算
-
语法:
-
声明在computed配置项中,一个计算属性对应一个函数
-
使用和其他普通属性一样使用
new Vue({ el:"", data:{ }, computed:{ 计算属性名(){ 基于现有数据,编写求值逻辑 return 结果 } } }) 在使用中:{{计算属性名}}
-
示例:
<body>
<div id="app">
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item,index) in list" :key="item.id">
<td>{{item.name}}</td>
<td>{{item.num}}个</td>
</tr>
</table>
<span>礼物总数:{{total}}个</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
list: [
{
id: 1, name: '篮球', num: 4
},
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 }
]
},
computed: {
total() {
let number = 0;
// 计算总数
return this.list.reduce((number, item) => number + item.num, 0)
}
}
})
</script>
(2)computed计算属性和method方法:
-
computed计算属性
- 作用:封装了一段对于数据的处理,求得一个结果
- 语法:
- 写在computed配置项
- 作为属性,直接使用:
- js中使用计算属性: this.计算属性
- 模板中使用计算属性:{{计算属性}}
-
methods方法
- 作用:给Vue实例提供一个方法,调用以处理业务逻辑。
- 语法:
- 写在methods配置项中
- 作为方法调用
- js中调用:this.方法名()
- 模板中调用 {{方法名()}} 或者 @事件名=“方法名”
-
计算属性优势
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
-
对比总结
1.computed有缓存特性,methods没有缓存
2.当一个结果依赖其他多个值时,推荐使用计算属性
3.当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数
(3)计算属性完整写法
既然计算属性为属性,那么它既可以用来获取,也可以用来修改咯。
计算属性默认的简写,只能读取访问,不能修改。
如果要 “修改” → 需要写计算属性的完整写法
1.3.9 watch 侦听器(监视器)
作用:监视数据变化,执行一些业务逻辑或异步操作。
需求:输入内容,实时翻译。
(1)语法:
- 简单写法:简单类型数据,直接监视
- 完整写法:添加额外配置
(2)简单写法
data: {
words: '苹果',
obj: {
words: '苹果'
}
},
watch: {
// 该方法会在数据变化时,触发执行
数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
'对象.属性名' (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}
(3)防抖:延迟执行
简介:干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行。
案例:实时翻译
<scropt>
new Vue({
el: "#app",
data: {
obj: {
words: ''
},
language: 'german',
myRes: '',//存放翻译的结果
// timer: null //延时器 可省略在data里面写入
},
// 监视
watch: {
// 此方法会在数据变化时,进行调用
// timer 可以不用存在data里面 直接写下面的this.timer也可以,相当于直接给对象加了timer属性
'obj.words'(newValue, oldValue) {
// 加入一个延时器 都会侦听
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
//只有这个setTimeOut出现的问题:就是你只要输入了就会有效,只不过只是延迟了翻译而已
// 我需要的是:停稳了才执行,如果中间有打断的,那么要清空之前的计时器
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: this.obj.words,
lang: this.language
}
})
this.myRes = res.data.data
console.log(res.data.data);
}, 300)
}
}
})
</script>
(4)完整写法
完整写法:添加额外配置。
-
deep:true 对复杂类型进行深度监听
-
immdiate:true 初始化 立刻执行一次 (是否需要立即执行一个handler)
data: { obj: { words: '苹果', lang: 'italy' }, }, watch: {// watch 完整写法 对象: { deep: true, // 深度监视 immdiate:true,//立即执行handler函数 handler (newValue) { console.log(newValue) } } }
案例:输入内容,修改语言,能实时翻译
(一个结果,多个条件 把条件数据写在对象当中)
<script>
new Vue({
el: "#app",
data: {
obj: {
words: '',
language: 'german'
},
myRes: '',//存放翻译的结果
},
watch: {
obj: {
deep: true,
immediate: true,//一进入页面 立即执行 handel
handler(newValue) {
console.log(newValue);
clearTimeout(this.timer)
this.timer = setTimeout(() => {
axios({
// method:'post',
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: newValue
// words: this.obj.words,
// lang: this.obj.language
}).then(result => {
// console.log(result);
this.myRes = result.data.data
console.log(this.obj.language);
})
}, 300)
}
}
}
})
</script>
(5)两者写法的对比
//简单写法
watch: {
// 该方法会在数据变化时,触发执行
数据属性名 (newValue, oldValue) {
一些业务逻辑 或 异步操作。
},
'对象.属性名' (newValue, oldValue) {
一些业务逻辑 或 异步操作。
}
}
//完整写法:
watch: {// watch 完整写法
对象: {//对对象里面的所有进行监视
deep: true, // 深度监视
immdiate:true,//立即执行handler函数
handler (newValue) {
console.log(newValue)
}
}
}
1.4 生命周期
什么时候可以发送初始化渲染请求?(越早越好)什么时候可以开始操作dom?(至少dom得渲染出来)
Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程.
1.4.1 生命周期阶段
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
(1)创建阶段:创建响应式数据
(2)挂载阶段:渲染模板
(3)更新阶段:修改数据,更新视图
(4)销毁阶段:销毁Vue实例
1.4.2 生命周期函数(钩子函数)
Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行自己的代码
生命周期有四个阶段,钩子函数有八个,每个阶段的前后都会有一个函数。
重要俩个:
(1)created(发送初始化渲染请求,beforeCreate数据还没准备好呢)
(2)mounted (beferMount阶段dom还没有准备好,所以操作dom在mounted阶段)
<body>
<div id="app">
<h2>{{title}}</h2>
<button @click="count--">-</button>
<span class="num">{{count}}</span>
<button class="btn" @click="count++">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
count: 100,
title: '计数器'
},
// 1.创建阶段(准备数据)
beforeCreate() {
console.log("1.1准备数据之前" + this.count);
},
created() {
console.log("1.2 数据准备好了" + " " + this.count + this.title);
},
// 2.挂载阶段(渲染模板)
beforeMount() {
const num = document.querySelector('.num').innerText
console.log("2.1 在渲染之前" + num);
// 在渲染之前{{count}}
},
mounted() {
const num = document.querySelector('.num').innerText
console.log("2.2 模板渲染完之后" + num);
// 模板渲染完之后100
},
//可以操作dom了
// 3.更新阶段
beforeUpdate() {
const num = document.querySelector('.num').innerText
console.log("数据还没被更新,拿到的数据为原数据" + num);
},
updated() {
const num = document.querySelector('.num').innerText
console.log("数据更新了拿到的数据为新数据" + num);
},
// 4.销毁阶段
beforeDestroy() {
console.log("销毁实例之前释放资源");
},
destroyed() {
? console.log("销毁实例");
}
})
</script>
</body>
(1)created应用
created:响应式数据准备好了,可以开始发送初始化渲染请求
// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
const app = new Vue({
el: '#app',
data: {
list: []
},
async created() {
// 1.发送请求。获取数据
const res = await axios.get('http://hmajax.itheima.net/api/news')
console.log(res);
// 2.将数据更新给data里面的list
this.list = res.data.data
console.log(this.list);
},
})
(2)mounted应用
//一进入页面,立刻能获取焦点(焦点-操作dom)
const app = new Vue({
el: '#app',
data: {
words: ''
},
// 核心思路:
// 1. 等input框渲染出来 ---渲染之后使用:mounted 钩子
// 2. 让input框获取焦点 inp.focus()
mounted() {
//找到input
document.getElementById('inp').focus()
}
})
(3)案例的总结
-
关于echarts
-
1.引入文件
-
2.为图表准备一定宽高的容器盒子
-
3.准备图表。
this.myChart = echarts.init(document.getElementById('main'))
-
4.指定图表的配置项和数据 使用option={}
-
-
使用刚指定的配置项和数据显示图表
this.myChart.setOption(option)
-
-
异步数据如何同步到图表?
在图表初始化后不管任何时候只要通过工具异步获取数据后通过 setOption 填入数据和配置项就行。 // 更新图表 // { value: 1048, name: '防晒霜' }, // { value: 735, name: '球鞋' }, this.myChart.setOption({ series: [ { data: this.list.map(item => ({ value: item.price, name: item.name })) } ] })
-
1.5 工程化开发和脚手架Vue CLi
1.5.1 开发vue的两种方式:
-
核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
-
工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。
工程化开发模式优点:
提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等
工程化开发模式问题:
- webpack配置不简单
- 雷同的基础配置
- 缺乏统一的标准
为了解决以上问题,所以我们需要一个工具,生成标准化的配置
1.5.2 Vue CLI脚手架
-
Vue CLI 是Vue官方提供的一个全局命令工具可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
-
好处:
- 开箱即用,零配置
- 内置babel等工具
- 标准化的webpack配置
-
使用步骤:
- 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
- 查看vue/cli版本: vue --version
- 创建项目架子:vue create project-name(项目名不能使用中文)
- 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)
1.5.3 组件化开发
组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。
好处:便于维护,利于复用 → 提升开发效率。
如:下面这个页面,可以把所有的代码都写在一个页面中,但是这样显得代码比较混乱,难易维护。咱们可以按模块进行组件划分
组件分类:普通组件、根组件。
1.5.4 根组件
(1)介绍
根组件:App.vue整个应用最上层的组件,包裹所有普通小组件.
(2)组件的组成:
-
三部分构成(结构、行为和样式)
-
template:结构 (有且只能一个根元素)
-
script: js逻辑 export default{}
-
style: 样式 (可支持less,需要装包)
-
让组件支持less
(1) style标签,lang=“less” 开启less功能
(2) 装包(两个 less和less-loader): yarn add less less-loader -D 或者npm i less less-loader -D
-
<template> <div class="box" @click="fn"></div> <!-- //只能有一个根元素 --> </template> <script> // 导出的是当前组件的配置项 // 可以提供data(特殊) methods,computed,watch 生命周期,八大钩子 export default{ methods:{ fn(){ alert('点击了!') } } } </script> <style> .box{ width: 400px; height: 400px; background-color: pink; } </style>
-
1.5.5 普通组件的注册使用
- 注册的两种方式:
- 1.全局注册:所有的组件内都能使用
- 2.局部注册:只能在注册的组件内使用
- (1)创建.vue文件
- (2)在使用的组件内导入并注册
(1)局部注册:
组件名规范 —> 大驼峰命名法, 如 HmHeader
使用方式:当成html标签使用即可 <组件名></组件名>
例如:
import 组件对象 from ./vue文件路径
比如import HmHeader from './components/HmHeader'
export default{
components:{
'组件名':组件对象,
HmHeader:HmHeader,
HmHeader
}
}
(2)全局注册:
全局注册的组件,在项目的任何组件中都能使用.
-
使用步骤:
-
创建vue组件
-
在main.js中全局注册
// 导入需要全局注册的组件 import HmButton from './components/HmButton' Vue.component('HmButton', HmButton)
-
使用:当成HTML标签直接使用
<组件名></组件名>
-
1.5.6 scoped样式冲突
(1)组件注意点
- 组件三大组成成分
- 结构template:只有一个根元素
- 样式style:默认是全局样式,影响所有组件。局部样式:scoped下样式,只作用于当前组件
- 逻辑script:el是根实例独有的,data是一个函数,其他配置项是一样的
(2)scoped 样式冲突
- 写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。
- 全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
- 局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
<template>
<div class="base-one">
BaseOne
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
(3)scoped原理
-
当前组件模板的所有元素,都会被加上一个自定义属性。
-
最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
-
当前组件内标签都被添加data-v-hash值 的属性
-
css选择器都被添加 [data-v-hash值] 的属性选择器
-
1.5.7 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(){
return {
count:999
}
}
}
</script>
<style>
</style>
1.5.8 组件通信
(1)概念:
- 组件通信,就是指组件与组件之间的数据传递
- 组件的数据是独立的,无法直接访问其他组件的数据。
- 想使用其他组件的数据,就需要组件通信
- 组件之间有什么关系呢?对应的通信逻辑有哪些?
(2)组件关系与通信逻辑
-
组件关系分类:
-
父子关系
-
非父子关系
-
(2.1)父子通信逻辑-父传子数据
- 父组件通过 props 将数据传递给子组件
- 子组件利用 $emit 通知父组件修改更新
- 步骤
- 在使用子组件的时候,以添加属性的方式来传值。
- 子内部通过props接收
- 子组件的模板中直接使用props接收到的值。
- 注意:使用props: props:[‘title’] 数组包起来,变量放引号。
(2.2)父子通信逻辑-子通知父修改
子组件利用 $emit 通知父组件,进行修改更新
- 步骤:
- $emit触发事件,给父组件发送消息通知
- 父组件监听$emit触发的事件
- 提供处理函数,在函数的形参中获取传过来的参数
(3)Prop详解
- 概念:组件上 注册的一些 自定义属性。向子组件传递数据
- 特点:
- 可以 传递 任意数量 的prop
- 可以 传递 任意类型 的prop
(4)props校验
为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误
-
语法:
-
类型校验
-
非空校验
-
默认值
-
自定义校验
-
(5)props校验完整写法
不局限于类型的校验
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值, // 默认值
validator (value) {
// 自定义校验逻辑
return 是否通过校验
}
}
},
示例:
<script>
export default {
// 完整写法(类型、默认值、非空、自定义校验)
props: {
w: {
type: Number,
//required: true,
default: 0,
//注意:default和required一般不同时写(因为当时必填项时,肯定是有值的)
validator(val) {
// console.log(val)
if (val >= 100 || val <= 0) {
console.error('传入的范围必须是0-100之间')
return false
} else {
return true
}
},
},
},
}
</script>
(6)prop和data、单向数据流
都可以给组件提供数据,data 的数据是自己的 → 随便改 。prop 的数据是外部的 → 不能直接改,要遵循 单向数据流
- 单向数据流:父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的
(7)小黑记事本案例总结:
-
持久化存储。将数据保存到本地。watch深度监视list的变化,一旦变化,本地存储。一进入页面,优先读取。
data () { return { list:JSON.parse( localStorage.getItem('list')) || [{ id:1,name:'打篮球' },{id:2,name:'写作业'}, {id:3,name:'学前端'} ] } }, watch:{ list:{ // 深度监视: deep:true, immediate:true, handler(newValue){ // 一旦变化,立即执行 将数组转为json字符串存储 localStorage.setItem('list',JSON.stringify(newValue)) } } },
-
总结:
-
(1)拆分基础组件-
-
新建组件
-
拆分组件结构
-
导入、注册、使用
导入:import 注册: 全局:在main.js。注册:Vue.component 局部:在需要的组件注册。注册:在script里面compontens:{} 使用:<组件名></组件名>
-
-
(2)渲染实现任务
- 提供数据(公告父组件)
- 父传子:
- 在使用的子组件上添加属性 : 子组件使用的属性名=“父组件传的数据”,
- 子组件接收,在script里面,使用props属性
- 子组件使用,同vue里面的使用
- 子通知父:
- 在子组件定义事件,使用this.$emit(‘事件名’,参数)
- 把事件传给父。在父组件里面使用的子组件里面添加 @子组件定义的事件名=“在父组件实现的事件名”
- 父组件在methods里面实现相应逻辑
- 父传子:
- 提供数据(公告父组件)
-
对于数组的一些方法:
- 通过id删除数组
this.list=this.list.filter(item=>item.id!==id)
-
unshift添加数组元素
this.list.unshift({ id:+new Date(), name:value })
其余笔记,正持续更新~一枚萌新正持续成长中!