目录
1、生命周期

生命周期函数(钩子函数)
初始化渲染请求越早越好(before creat阶段响应式数据还没有准备好),要在响应式数据准备好才能进行,因此在created中执行。

<div id="app">
<h3>{{ title }}</h3>
<div>
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100,
title: '计数器'
},
// 1. 创建阶段(准备数据)
beforeCreate () {
console.log('beforeCreate 响应式数据准备好之前', this.count)
},
created () {
console.log('created 响应式数据准备好之后', this.count)
// this.数据名 = 请求回来的数据
// 可以开始发送初始化渲染的请求了
},
// 2. 挂载阶段(渲染模板)
beforeMount () {
console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML)
},
mounted () {
console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML)
// 可以开始操作dom了
},
// 3. 更新阶段(修改数据 → 更新视图)
beforeUpdate () {
console.log('beforeUpdate 数据修改了,视图还没更新', document.querySelector('span').innerHTML)
},
updated () {
console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML)
},
// 4. 销毁阶段 app.$destroy() 并不会把之前渲染的页面情况,会把所有的监听事件等等销毁
beforeDestroy () {
console.log('beforeDestroy, 卸载前')
console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
},
destroyed () {
console.log('destroyed,卸载后')
}
})
</script>
created应用 - 初始化渲染
created:响应式数据准备好了,才可以开始发送初始化渲染请求。
<div id="app">
<ul>
<li v-for="(item, index) 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>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// 接口地址: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')
// 2. 更新到 list 中,用于页面渲染 v-for
this.list = res.data.data
}
})
</script>
钩子函数应用 - 获取焦点
mounted:模板渲染完成,可以开始操作DOM。
<body>
<div class="container" id="app">
<div class="search-container">
<img src="https://www.itheima.com/images/logo.png" alt="">
<div class="search-box">
<input type="text" v-model="words" id="inp">
<button>搜索一下</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
words: ''
},
// 核心思路:
// 1. 等input框渲染出来 mounted 钩子
// 2. 让input框获取焦点 inp.focus()
mounted () {
document.querySelector('#inp').focus()
}
})
</script>
</body>
2、案例:小黑记账清单
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<!-- 添加资产 -->
<form class="my-form">
<input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" />
<input v-model.number="price" type="text" class="form-control" placeholder="消费价格" />
<button @click="add" type="button" class="btn btn-primary">添加账单</button>
</form>
<table class="table table-hover">
<thead>
<tr>
<th>编号</th>
<th>消费名称</th>
<th>消费价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
<td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td>
<td><a @click="del(item.id)" href="javascript:;">删除</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td>
</tr>
</tfoot>
</table>
</div>
<!-- 右侧图表 -->
<div class="echarts-box" id="main"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 接口文档地址:
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
*
* 功能需求:
* 1. 基本渲染
* (1) 立刻发送请求获取数据 created
* (2) 拿到数据,存到data的响应式数据中
* (3) 结合数据,进行渲染 v-for
* (4) 消费统计 => 计算属性
* 2. 添加功能
* (1) 收集表单数据 v-model
* (2) 给添加按钮注册点击事件,发送添加请求
* (3) 需要重新渲染
* 3. 删除功能
* (1) 注册点击事件,传参传 id
* (2) 根据 id 发送删除请求
* (3) 需要重新渲染
* 4. 饼图渲染
* (1) 初始化一个饼图 echarts.init(dom) mounted钩子实现
* (2) 根据数据实时更新饼图 echarts.setOption({ ... })
*/
const app = new Vue({
el: '#app',
data: {
list: [],
name: '',
price: ''
},
computed: {
totalPrice () {
return this.list.reduce((sum, item) => sum + item.price, 0)
}
},
created () {
// const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
// params: {
// creator: '小黑'
// }
// })
// this.list = res.data.data
this.getList()
},
mounted () {
this.myChart = echarts.init(document.querySelector('#main'))
this.myChart.setOption({
// 大标题
title: {
text: '消费账单列表',
left: 'center'
},
// 提示框
tooltip: {
trigger: 'item'
},
// 图例
legend: {
orient: 'vertical',
left: 'left'
},
// 数据项
series: [
{
name: '消费账单',
type: 'pie',
radius: '50%', // 半径
data: [
// { value: 1048, name: '球鞋' },
// { value: 735, name: '防晒霜' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
},
methods: {
async getList () {
const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
params: {
creator: '小黑'
}
})
this.list = res.data.data
// 更新图表
this.myChart.setOption({
// 数据项
series: [
{
// data: [
// { value: 1048, name: '球鞋' },
// { value: 735, name: '防晒霜' }
// ]
data: this.list.map(item => ({ value: item.price, name: item.name}))
}
]
})
},
async add () {
if (!this.name) {
alert('请输入消费名称')
return
}
if (typeof this.price !== 'number') {
alert('请输入正确的消费价格')
return
}
// 发送添加请求
const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
creator: '小黑',
name: this.name,
price: this.price
})
// 重新渲染一次
this.getList()
this.name = ''
this.price = ''
},
async del (id) {
// 根据 id 发送删除请求
const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)
// 重新渲染
this.getList()
}
}
})
</script>
</body>
3、工程化开发入门

按 win+x 然后,点击(Windows)终端管理员 ,用yarn global add @vue/cil 或 npm i @vue/cli -g 全局安装
脚手架目录文件介绍&项目运行流程

public下面的index.html 如下:
<body>
<!-- 兼容:给不支持js的浏览器一个提示 -->
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<!-- Vue所管理的容器:将来创建结构动态渲染这个容器 -->
<div id="app">
<!-- 工程化开发模式中:这里不再直接编写模板语法,通过 Vue.app 提供结构渲染 -->
</div>
<!-- built files will be auto injected -->
</body>
main.js 文件:
文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
import App from './App.vue':导入App.vue 根组件
Vue.config.productionTip = false:提示:当前处于什么环境(生产环境/开发环境)
.$mount('#app') 与el: '#app' 作用相同
组件化开发&根组件
组件化:一个页面拆分成一个个组件,每个组件都有独立的结构、样式、行为。便于维护,复用
分类:普通组件、根组件(整个应用最上层的组件,包裹所有普通小组件)

App.vue 文件的组成部分

template:结构(有且只能一个根元素,Vue2是这样的,Vue3已经没有这个特性了)
script:js逻辑
style:样式(可支持less,需要装包)

script 中 export default {} 导出的是当前组件的配置项,可以提供data(特殊) methods compute watch 生命周期
普通组件的注册使用
局部注册
组件名使用大驼峰命名

全局注册

编写导入的代码,往代码的顶部编写(规范)
在main.js中导入
import Vue from 'vue'
import App from './App.vue'
//编写导入的代码,往代码的顶部编写(规范)
import Button from './components/Button.vue'
Vue.config.productionTip = false
// 进行全局注册 Vue.component(组件名,组件对象)
Vue.component('Button', Button)
new Vue({
render: h => h(App),
}).$mount('#app')
在使用组件的地方调用

4、组件的三大组成部分

组件的样式冲突scoped


scoped原理:
1、给当前组件模板的所有元素都会被添加上一个自定义属性 data-v-hash 值
2、css选择器后面被自动处理,添加上了属性选择器 eg: div[ data-v-hash值 ]
data函数

5、组件通信
--- 组件与组件之间的数据传递
组件关系:父子关系、非父子关系
组件通信解决方案:父子关系 --- props 和 $emit ;非父子关系 --- provide & inject / eventbus
通用解决方案:Vuex(适合复杂业务场景)
父子组件通信

父传子
props 实际上就是给组件标签身上加上自定义属性

子传父
子组件不能直接修改数据,要通过$emit 向父组件发送消息通知,父组件对消息进行监听,提供处理函数,提供逻辑

props详解
作用:向子组件传递数据
特点:可以传递任意数量、任意类型的props
props传的是属性名

props校验
语法:类型校验、非空校验、默认值、自定义校验
类型校验语法:

完整语法:

props & data、单向数据流

自己的数据在data中,可以改;props中的数据是父组件的,不能改。
单向数据流:父组件的prop更新,会单向向下流动,影响到子组件。
渲染数据注意:提供数据是提供在公共的父组件 App.vue中;然后通过父传子,使用 v-for 渲染。
非父子通信 - event bus 事件总线
作用:非父子组件之间,进行简易消息传递(复杂场景使用 Vuex)

非父子通信 - provide & inject
作用:跨层级共享数据

6、v-model 详解
v-model原理
原理:一种语法的简写,eg:应用在输入框上,就是value属性和input事件的合写;如果应用在复选框上,就是checked属性和change事件的合写。
作用:提供数据的双向绑定。数据变,视图跟着变 :value;视图变,数据跟着变@input。

表单类组件封装
数据在父组件中(以便后续表单提交),v-model不可以直接和父组件的数据绑定(因为v-odel是双向绑定,是可以修改的,但是子组件不能直接修改父组件的数据),将v-model拆解绑定数据,监听数据的变化,子传父,由父组件修改数据。

v-model简化代码
实现子组件和父组件数据双向绑定。

7、.sync修饰符
作用:可以实现子组件和父组件数据的双向绑定,简化代码
特点:prop属性名,可以自定义,非固定为value


8、ref 和 $refs
作用:利用ref和$refs可以用于获取dom元素或组件实例
特点:查找范围 -> 当前组件内(更精确稳定)

9、Vue异步更新、$nextTick

点击编辑后,输入框不能聚焦,因为Vue是异步更新DOM(提升性能)
$nextTick:等DOM更新后,立刻会触发执行此方法里的函数体。
使用setTimeout也可以,但是不精准。

1291

被折叠的 条评论
为什么被折叠?



