vue学习笔记整理
一、安装
1、CDN
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
2、npm
npm install vue
若报错,先执行npm init -f ,再执行npm install vue
3、开发版本
重要: GitHub 仓库的 /dist
文件夹只有在新版本发布时才会提交。如果想要使用 GitHub 上 Vue 最新的源码,需要自己构建!
git clone https://github.com/vuejs/vue.git node_modules/vue
cd node_modules/vue
npm install
npm run build
二、介绍
1、vue
Vue 是一套用于构建用户界面的渐进式框架。
运行.vue文件
D:\workplace\vue>vue serve
2、Vue特点
易用: 会html、css、js即可上手
灵活: 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩
高效: 20KB min + gzip 运行大小,超快虚拟DOM,最省心的优化
库和框架的区别
框架:是一套完整的解决方案,对项目的侵入性比较大,项目如果需要换框架,需重新搭建整个项目
库:提供一个小功能,对项目的入侵性比较小,如果某个库无法完成某些需求,可以很容易切换到其他库实现需求
引入vue
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或者
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
3、插值表达式{{ }}
(1) {{ string | number | booleans | 数组 | object | undefined | null | 表达式 }}
里面可以放的东西
{{ 'a' }} 字符string
{{ 12 }} number
{{ true } 布尔值
{{ [1,2,3] }} 数组
{{ {a:1, b:10 } }} 对象object
{{ undefined }}
{{ null }}
{{ 1+1 }} 表达式
(2) v-text与插值表达式{{}}的区别
v-text会覆盖元素中原来的内容,但插值表达式只会替换自己的占位符不会把整个元素清空。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue测试</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>+++{{msg}}---</p>
<p v-text="msg">+++---</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '123'
}
});
</script>
</body>
</html>
+++123---
123
4、vue指令
(1)绑定
v-bind 绑定属性(v-bind <==> ?
如:绑定图片:<img v-bind:src="imgUrl" v-bind:alt="name" /> 或者
<img :src="imgUrl" :alt="name" />
当图片出现错误的时候,会显示图片的name
特殊的:class、style
class:
1、绑定多个class用数组:<h4 :class="[h4Class, h4Width]">{{ name }}</h4>
2、对象:<h4 :class="{red: true}">{{ name }}</h4>
3、对象和数组:<h4 :class="[{red: true}, h4Width]">{{ name }}</h4>
4、多元表达式:<h4 :class="[h4Flag ? 'red' : '' , h4Width]">{{ name }}</h4>
style:
对象: <img :src="imgUrl" :alt="name" :style="{width: imgWidth, border: '10px solid red'}"/>
数组: <img :src="imgUrl" :alt="name" :style="[{width: imgwidth}, imgStyle]"/> <script> data: { imgStyle: {border: '10px solid red'} }</script>
v-on:xxx监听事件(v-on <==> @)
<button v-on:click="handleClick">点击</button>
等价于 <button @click="handleClick">点击</button>
(2)条件渲染
v-if 能够控制元素的显示与隐藏
<button @click="handleClick">{{ text }}</button>
<div class="box red" v-if="show"></div>
data: {
show: true,
text: '隐藏'
},
methods: {
handleClick () {
this.show = !this.show;
this.text = this.show ? '隐藏' : '显示';
}
}
v-else
<button @click="handleClick">{{ text }}</button>
<div class="box red" v-if="show"></div>
<div class="box green" v-else></div>
v-else-if
<div class="box red" v-if="num === 0"></div>
<div class="box yellow" v-else-if="num === 1"></div>
<div class="box green" v-else></div>
data: {
show: true,
text: '隐藏',
num: 0
},
methods: {
handleClick () {
this.show = !this.show;
this.text = this.show ? '隐藏' : '显示';
}
}
v-show 通过添加一个style:display来控制元素显示与隐藏
<div class="box red" v-show="show"></div>
v-if与v-show的区别
-
v-if 控制dom的移除和添加,v-show控制dom的样式显示与隐藏(display)
- 频繁地切换显示与隐藏使用v-show
- 只判断一次时,使用v-if
-
v-if可以写在template上,v-show不行,写了也没用
(3)列表渲染
v-for:arr、obj、num、string
循环数组 arr: item, index in arr
<ul>
<li v-for="(item, index) in arr">{{ item }} --- {{ index }}</li>
</ul>
const vm = new Vue({
el: '#app',
data: {
arr: ['html', 'js', 'vue']
}
})
循环对象
<h4 v-for="(value, key, index) in obj">{{ value }} --- {{key}} --- {{index}}</h4>
const vm = new Vue({
el: '#app',
data: {
obj: {
name: 'yitian',
age: 18,
looks: 'beautiful'
}
}
})
key:name value:'yitian'
循环数字
<p v-for="item in 10">{{ item }}</p>
数字1到10打印出来
循环字符串
<div v-for="item in 'yitian'">{{ item }}</div>
注意:key:必须是num或字符串且唯一
5、更改数组
(1)不能通过索引的方式去更改数组,这样不会渲染
(2)不能通过更改长度的方式去更改数组,这样不会渲染
(3)数组变异方法
- pop
- shift
- unshift
- splice
- sort
- reverse
- push
6、更改对象
(1)向对象内添加或者删除属性,不会渲染页面
(2) vm.$set 添加一个属性和值
set方法还可以为对象添加属性和值
<script>
export default {
data(){
return {
obj:{
name:'xiaoming'
}
}
},
methods:{
change(){
this.$set(this.obj,'age',12)
console.log(this.obj);{name:xiaoming,age:12}
}
}
}
</script>
Object.defineProperty(obj, prop, desc)
obj 需要定义属性的当前对象
prop 当前需要定义的属性名
desc 属性描述符
(3)Object.assign(ES6语法),添加多个属性和值
<script>
export default {
data(){
return {
obj:{
name:'xiaoming'
}
}
},
methods:{
change(){
this.obj=Object.assign({},this.obj,{
height:180,
eq:200
})
}
}
}
</script>
7、双向数据绑定
(1) v-model 实现数据的双向绑定
1) text
value+@ input 的语法糖
<input type="text" v-model="value"/>
<span>{{ value }}</span>
data: {
value: 'yitian'
}
2) checkbox
一个选项
<input type="checkbox" v-model="checked" />
{{ checked }}
data: {
checked: true
}
复/多选框
for 属性规定 label 与哪个表单元素绑定。
<label for="html" >html</label>
<input type="checkbox" value="html" id="html" v-model="checkedList"/>
<label for="js" >js</label>
<input type="checkbox" value="js" id="js" v-model="checkedList"/>
<label for="vue" >vue</label>
<input type="checkbox" value="vue" id="vue" v-model="checkedList"/>
{{ checkedList }}
data: {
checkedList: []
}
3)单选框 radio
<label for="html">html</label>
<input type="radio" id="html" value="html" v-model="picked"/>
<label for="js">js</label>
<input type="radio" id="js" value="js" v-model="picked"/>
<label for="vue">vue</label>
<input type="radio" id="vue" value="vue" v-model="picked"/>
{{ picked }}
data: {
picked: ''
}
4)select下拉框
单选
<select name="" id="" v-model="selected">
<option value="" disabled>请选择</option>
<option value="html">html</option>
<option value="js">js</option>
<option value="vue">vue</option>
</select>
{{ selected }}
data: {
selected: ''
}
多选
<select name="" id="" v-model="selectedList" multiple>
<option value="html">html</option>
<option value="js">js</option>
<option value="vue">vue</option>
</select>
{{ selectedList }}
data: {
selectedList: ''
}
(2) textarea
<textarea v-model="content"></textarea>
{{ content }}
data: {
content: ''
}
8、计算属性和侦听器
(1) watch侦听器
{{ desc }}
{{ looks }}
data: {
name: '一天',
age: 24,
looks: 'handsome',
desc: '姓名: 一天 年龄: 24'
},
watch: {
name() {
this.desc = `姓名: ${this.name} 年龄: ${this.age}`;
}
}
(2) computed 计算属性
data: {
name: '一天',
age: 24,
looks: 'handsome',
},
computed: {
desc () {
return `姓名: ${this.name} 年龄: ${this.age}`;
}
}
}
(3) 查找顺序 data > methods > computed
methods: 想要去写一些逻辑,比如说要去触发一个事件的时候,或者在某一个函数里面再去写另一个函数作为封装的时候
computed: 想要得到一个新的数据,而且拿过来就可以使用
watch: 当想要在某一个事件改变的时候,去做一个什么什么样的事情的时候
9、组件数据传递和属性校验
全局组件 局部组件
(1) 全局组件
component
<div id="app">
<hello-world></hello-world>
<hello-world></hello-world>
<hello-world></hello-world>
</div>
//Vue.component('组件的名字',{对象:组件的一些配置参数})
Vue.component('HelloWorld', {
data() {
return {
msg: 'hello'
}
},
//组件的模版即结构
template: `
<div>
<button @click="handleClick">点击</button>
<span>{{ msg }}</span>
</div>
`,
methods: {
handleClick () {
this.msg = 'yitian';
}
}
})
const vm = new Vue({
el: '#app',
data: {
},
})
(2) 局部组件
components
const vm = new Vue({
el: '#app',
data: {
},
components: {
'HelloWorld': {
template: `
<div>
hello
</div>
`
}
}
})
注意:它是先使用局部组件,再去找全局组件
(3) 属性校验
components: {
myContent: {
// props: ['title', 'content'],
// props属性校验
props: {
title: {
type: String,
// default:规定默认值
default: '山山水水'
},
content: {
type: Number,
required: true,
validator (val){
return val > 10000
}
},
number: {
type: Number
},
obj: {
type: Object
}
},
}
}
}
(4) 父 -> 子 传值 props, 校验, v-bind=“object”
<div id="app">
<my-content v-bind="childrenInfo"></my-content>
</div>
const vm = new Vue({
el: '#app',
data: {
childrenInfo: {
title: '一天',
content: 78525,
number: 0,
obj: { a:1, b:10}
}
},
components: {
myContent: {
// props: ['title', 'content'],
// props属性校验
props: {
title: {
type: String,
// default:规定默认值
default: '山山水水'
},
content: {
type: Number,
required: true,
validator (val){
return val > 10000
}
},
number: {
type: Number
},
obj: {
type: Object
}
},
data () {
return {
ownNumber: this.number
}
},
template: `
<div>
<h4>{{ title }}</h4>
<p>{{ content }}</p>
<div>{{ ownNumber }}</div>
{{ obj }}
<button @click="handleClick">add</button>
</div>
`,
methods: {
handleClick() {
this.ownNumber ++;
// this.obj.a = 100;
}
}
}
}
})
(5)子 -> 父 传值 $emit(‘handle’, value)
直接子组件告诉父组件做什么,由父组件去做
<div id="app">
<my-content v-bind="childrenInfo" @add="handleAdd"></my-content>
父组件内的number: {{ childrenInfo.number }}
<button @click="handleClick">点击</button>
</div>
const vm = new Vue({
el: '#app',
data: {
childrenInfo: {
title: '一天',
content: 78525,
number: 0,
obj: { a:1, b:10}
}
},
methods: {
handleAdd(num){
this.childrenInfo.number += num;
},
handleClick() {
this.childrenInfo.title = '是一天吖'
}
},
components: {
myContent: {
// props: ['title', 'content'],
// props属性校验
props: {
title: {
type: String,
// default:规定默认值
default: '山山水水'
},
content: {
type: Number,
required: true,
validator (val){
return val > 10000
}
},
number: {
type: Number
},
obj: {
type: Object
}
},
data () {
return {
// ownNumber: this.number
}
},
template: `
<div>
<h4>{{ title }}</h4>
<p>{{ content }}</p>
<div>子组件内的number: {{ number }}</div>
{{ obj }}
<button @click="handleClick">add</button>
</div>
`,
methods: {
handleClick() {
// this.ownNumber += 10;
// 触发一个事件“add”
this.$emit('add', 10)
// this.obj.a = 100;
}
}
}
}
})
10、 ref引用
(1)dom的引用
dom对象的引用是该对象
<div id="app">
<square-change></square-change>
</div>
.square-box {
width: 100px;
height: 100px;
margin-top: 20px;
border: 2px solid #ccc;
}
const vm = new Vue({
el: '#app',
data: {
},
components: {
squareChange: {
data() {
return {
colorArr: ['red', 'orange', 'yellow', 'green']
}
},
template: `
<div>
<button
v-for="color in colorArr"
:key="color"
:style="{backgroundColor: color}"
@click="handleClick(color)"
:data-color="color"
>{{ color }}</button>
<div class="square-box" ref="squareBox"></div>
</div>
`,
methods: {
handleClick (color) {
// const color = e.target.dataset.color;
const squareBox = this.$refs.squareBox;
squareBox.style.backgroundColor = color;
}
}
}
}
})
(2)组件的引用
组件的引用是组件的实例对象
<div id="app">
<square-change ref="cmp"></square-change>
<button @click="handleClick">click</button>
</div>
const vm = new Vue({
el: '#app',
data: {
},
methods: {
handleClick() {
console.log(this.$refs.cmp.colorArr);
}
},
components: {
squareChange: {
data() {
return {
colorArr: ['red', 'orange', 'yellow', 'green']
}
},
template: `
<div>
<button
v-for="color in colorArr"
:key="color"
:style="{backgroundColor: color}"
@click="handleClick(color)"
:data-color="color"
>{{ color }}</button>
<div class="square-box" ref="squareBox"></div>
</div>
`,
methods: {
handleClick (color) {
// const color = e.target.dataset.color;
const squareBox = this.$refs.squareBox;
squareBox.style.backgroundColor = color;
}
}
}
}
})
注意:
1、ref同名时,后添加的会覆盖前面的,引用指向的是最后一个元素
2、在v-for时添加引用,引用的值类型是数组,数组里面是一个一个的对象、组件的实例对象
11、安装脚手架
cnpm install -g @vue/cli 安装脚手架,用于生成项目
cnpm install -g @vue/cli-service-global 快速原型开发 编译.vue文件
vue --version 查看vue-cli版本
运行.vue文件命令:
D:\workplace\vue>vue serve App.vue
12、进度条组件
(1)线性进度条 —百分比外显
//App.vue
<template>
<!-- <div>I am a cmp 我是一个组件 {{ msg }}</div>-->
<div>
<d-progress :percentage="50" />
<d-progress :percentage="80" status="success" />
<d-progress :percentage="40" status="exception" />
</div>
</template>
<script>
import DProgress from './Progress';
export default {
components: {
DProgress
},
data () {
return {
msg: 'hello world'
}
}
}
</script>
//Progress.vue
<template>
<div class="progress"
:class="[
status ? ` is-${status}` : ''
]"
>
<div class="progress-bar">
<div class="progress-bar__outer" :style="{height: strokeWidth + 'px'}">
<div class="progress-bar__inner" :style="barStyle"></div>
</div>
</div>
<div class="progress__text" :style="{fontSize: progressTextSize + 'px'}">
<template v-if="!status">{{ percentage }}%</template>
<i v-else class="icon" :class="iconClass"></i>
</div>
</div>
</template>
<script>
export default {
props: {
strokeWidth: {
type: Number,
default: 6
},
percentage: {
type: Number,
required: true,
default: 0,
// validator (value) {
// return value >= 0 && value<=100
// },
validator: val => val >= 0 && val <= 100
},
status: {
type: String
},
type: {
type: String,
default: 'line',
validator: val => ['circle', 'line'].includes(val)
}
},
computed: {
progressTextSize () {
return 12 + this.strokeWidth * 0.4;
},
stroke () {
let color;
switch (this.status) {
case 'success':
color = '#13ce66';
break;
case 'exception':
color = '#ff4949';
break;
default:
color = '#20a0ff';
}
return color;
},
barStyle () {
return {
width: this.percentage + '%',
backgroundColor: this.stroke
}
},
iconClass () {
if (this.type === 'line') {
return this.status === 'success'
? 'icon-circle-check'
: 'icon-circle-close'
} else {
return this.status === 'success'
? 'icon-check'
: 'icon-close'
}
}
}
}
</script>
<style>
@font-face {
font-family: 'icon'; /* project id 1455220 */
src: url('./icon/iconfont.eot');
src: url('./icon/iconfont.eot?#iefix') format('embedded-opentype'),
url('./icon/iconfont.woff2') format('woff2'),
url('./icon/iconfont.woff') format('woff'),
url('./icon/iconfont.ttf') format('truetype'),
url('./icon/iconfont.svg#iconfont') format('svg');
}
.icon {
font-family: 'icon' !important;
font-size: 16px;
font-style: normal;
}
.icon-circle-check::before {
content: '\e6d9';
}
.icon-circle-close::before {
content: '\e60d';
}
.icon-check::before {
content: '\e742';
}
.icon-close::before {
content: '\e61f';
}
.progress.is-success .progress__text {
color: #67c23a;
}
.progress.is-exception .progress__text {
color: #f56c6c;
}
.progress-bar {
display: inline-block;
/*width: calc(100% - 50px);*/
box-sizing: border-box;
width: 100%;
padding-right: 50px;
margin-right: -50px;
}
.progress-bar__outer {
border-radius: 100px;
background-color: #ebeef5;
}
.progress-bar__inner {
height: 100%;
border-radius: 100px;
transition: width .6s ease;
background-color: red;
}
.progress__text {
display: inline-block;
margin-left: 10px;
color: #606266;
}
</style>
(2)线性进度条 —百分比内显
//App.vue
<template>
<!-- <div>I am a cmp 我是一个组件 {{ msg }}</div>-->
<div>
<h2>线性进度条 --- 百分比外显</h2>
<d-progress :percentage="0" :show-text="false" />
<d-progress :percentage="50" color="orange" />
<d-progress :percentage="80" status="success" />
<d-progress :percentage="40" status="exception" />
<br />
<h2>线性进度条 --- 百分比内显</h2>
<d-progress :stroke-width="18" :percentage="10" text-inside="true" />
<d-progress :stroke-width="18" :percentage="40" text-inside="true" />
<d-progress :stroke-width="18" :percentage="60" status="success" text-inside="true" />
<d-progress :stroke-width="18" :percentage="80" status="exception" text-inside="true" />
</div>
</template>
<script>
import DProgress from './Progress';
export default {
components: {
DProgress
},
data () {
return {
msg: 'hello world'
}
}
}
</script>
<!--<style>-->
<!-- div {-->
<!-- background-color: red;-->
<!-- }-->
<!--</style>-->
//Progress.vue
<template>
<div class="progress"
:class="[
status ? ` is-${status}` : ''
]"
>
<div class="progress-bar">
<div class="progress-bar__outer" :style="{height: strokeWidth + 'px'}">
<div class="progress-bar__inner" :style="barStyle">
<!-- 内显-->
<div class="progress-bar__innerText" v-if="textInside && showText">{{ percentage }}%</div>
</div>
</div>
</div>
<div
class="progress__text"
:style="{fontSize: progressTextSize + 'px'}"
v-if="!textInside && showText"
>
<template v-if="!status">{{ percentage }}%</template>
<i v-else class="icon" :class="iconClass"></i>
</div>
</div>
</template>
<script>
export default {
props: {
strokeWidth: {
type: Number,
default: 6
},
percentage: {
type: Number,
required: true,
default: 0,
// validator (value) {
// return value >= 0 && value<=100
// },
validator: val => val >= 0 && val <= 100
},
status: {
type: String
},
type: {
type: String,
default: 'line',
validator: val => ['circle', 'line'].includes(val)
},
// 内显
textInside: {
type: Boolean,
default: false
},
showText: {
type: Boolean,
default: true
},
color: {
type: String
}
},
computed: {
progressTextSize () {
return 12 + this.strokeWidth * 0.4;
},
stroke () {
let color;
if (this.color) {
return this.color;
}
switch (this.status) {
case 'success':
color = '#13ce66';
break;
case 'exception':
color = '#ff4949';
break;
default:
color = '#20a0ff';
}
return color;
},
barStyle () {
return {
width: this.percentage + '%',
backgroundColor: this.stroke
}
},
iconClass () {
if (this.type === 'line') {
return this.status === 'success'
? 'icon-circle-check'
: 'icon-circle-close'
} else {
return this.status === 'success'
? 'icon-check'
: 'icon-close'
}
}
}
}
</script>
<style>
@font-face {
font-family: 'icon'; /* project id 1455220 */
src: url('./icon/iconfont.eot');
src: url('./icon/iconfont.eot?#iefix') format('embedded-opentype'),
url('./icon/iconfont.woff2') format('woff2'),
url('./icon/iconfont.woff') format('woff'),
url('./icon/iconfont.ttf') format('truetype'),
url('./icon/iconfont.svg#iconfont') format('svg');
}
.icon {
font-family: 'icon' !important;
font-size: 16px;
font-style: normal;
}
.icon-circle-check::before {
content: '\e6d9';
}
.icon-circle-close::before {
content: '\e60d';
}
.icon-check::before {
content: '\e742';
}
.icon-close::before {
content: '\e61f';
}
.progress.is-success .progress__text {
color: #67c23a;
}
.progress.is-exception .progress__text {
color: #f56c6c;
}
.progress-bar {
display: inline-block;
/*width: calc(100% - 50px);*/
box-sizing: border-box;
width: 100%;
padding-right: 50px;
margin-right: -50px;
}
.progress-bar__outer {
border-radius: 100px;
background-color: #ebeef5;
}
.progress-bar__inner {
height: 100%;
line-height: 1;
border-radius: 100px;
transition: width .6s ease;
text-align: right;
}
.progress-bar__innerText {
display: inline-block;
color: #fff;
font-size: 12px;
margin: 0 5px;
vertical-align: middle;
}
.progress__text {
display: inline-block;
margin-left: 10px;
color: #606266;
}
</style>
(3)环形进度条
三、Vue生命周期
beforeCreate :
在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用
完成实例初始化,初始化非响应式变量,元素DOM和数据都还没有初始化
this指向创建的实例
可以在这加个loading事件
data computed watch methods上的方法和数据均不能访问
created:
在实例创建完成后被立即调用。
在这一步,实例已完成以下配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调
然而,挂载阶段还没开始,$el属性目前不可见
实例创建完成
完成数据(data props computed)的初始化,导入依赖项
可访问data computed watch methods上的方法和数据
未挂载DOM,不能访问$el,$ref为空数组
可在这结束loading,还能做一些初始化,实现函数自执行
可以对data数据进行操作,可进行一些请求,但由于DOM未挂载,请求过多或者占用时间过长会导致页面线上空白。
若在此阶段进行的DOM操作一定要放在Vue.nextTick()的回调函数中
beforeMount:
在挂载开始之前被调用:相关的渲染函数首次被调用
有了el,编译了template/outerHTML
能找到对应的template,并编译完成render函数
el属性:检查vue配置,即new Vue{}里面的el项是否存在,有就继续检查template项,没有则等到手动绑定调用vm.$mount()
template: 检查配置中的template项,如果没有template进行填充被绑定区域,则被绑定区域的el对象的outerHTML(即整个#app DOM对象,包括<div id="app">和</div>标签)都作为被填充对象替换掉填充区域
mounted:
el 被新创建的 vm.$el 替换,挂载成功
完成创建vm.$el,和双向绑定
完成挂载DOM和渲染,可在mounted钩子对挂载的dom进行操作
即有了DOM且完成了双向绑定,可访问DOM节点,$ref
可在这发起后端请求,拿回数据,配合路由钩子做一些事情
可对DOM进行操作
beforeUpdate:
数据更新时调用
数据更新之前
可在更新前访问现有的DOM,如手动移除天价的事件监听器
updated:
组件 DOM 已经更新,组件更新完毕
完成虚拟DOM的重新渲染和打补丁
组件DOM已完成更新
可执行依赖的DOM操作
注意:不要在此函数中操作数据,会陷入死循环
activated:keep-alive组件激活时调用。该钩子在服务器渲染期间不被调用
在使用vue-router时,有时需要使用<keep-alive></keep-alive>来缓存组件状态,这个时候created钩子就不会被重复调用了
如果子组件需要在每次加载的时候进行某些操作,可以使用activated钩子触发
deactivated:keep-alive组件停用时调用。该钩子在服务器渲染期间不被调用
for keep-alive 组件被移除时使用
beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用
在执行app.$destroy()之前
可做一些删除提示,如:您确认删除xx吗?
可用于销毁定时器,解绑全局时间,销毁插件对象
destroyed:当vm.$destroy()被调用,开始拆卸组件和监听器,生命周期终结
当前组件已被删除,销毁监听事件 组件 事件子实例也被销毁
这时组件已经没有了,无法操作里面的任何东西
四、利用脚手架搭建项目
1、命令行生成项目
C:\Users\Admin>D:
D:\>cd workplace
D:\workplace>vue create vue-app
D:\workplace>"node" "D:\nodejs\node_cache\\node_modules\@vue\cli\bin\vue.js" create vue-app
? Your connection to the default npm registry seems to be slow.
Use https://registry.npm.taobao.org for faster installation? Yes
Vue CLI v3.12.0
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package.json
? Save this as a preset for future projects? Yes
? Save preset as: onlyBable
2、图形化界面生成项目
C:\Users\Admin>vue ui
创建 => 在此创建新项目 => 编辑信息之后,下一步 => 选择手动 => 功能界面,选择 Bable => 下一步,创建项目,不保留预设