结果: 把开发人员从繁琐的DOM操作中解放出来, 把关注点放在如何操作Model上, 大大提高我们的开发效率.
为了让IDEA识别Vue代码, 需要安装插件 Vue.js
新建一个空白文件夹, 拖拽到桌面Idea图标处, 打开
将vue.js复制到项目中, vue.js下载官网
这里下载的是开发版本
新建页面 quick_start.html -> 数据绑定机制验证
<body>
<div id="app">
<h1>欢迎{{message}}--{{name}}h1>
div>
<script src="vue.js">script>
<script>
//创建Vue对象
/**
* 1.创建Vue对象实例
* 2.我们在控制台输出vm对象, 看看该对象的结构! 数据在哪里 listeners在哪里
*/
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "hello-Vue!",
name: "赵志伟"
}
});
console.log("vm=>", vm);
console.log(vm._data.message);
console.log(vm._data.name);
console.log(vm.message);
console.log(vm.name);
script>
body>
需求: 演示v-bind 的使用, 可以绑定元素的属性
- 插值表达式是在标签体的
- 如果给标签属性绑定值, 则使用 v-bind 指令
<body>
<div id="app">
<h1>{{message}}h1>
<img v-bind:src="img_src" v-bind:width="img_width">
<img :src="img_src" :width="img_width">
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "Hello-温暖女孩!",
img_src: "1.jpg",
img_width: "200px"
}
});
console.log("vm=>", vm);
script>
<div id="app">
<h1>{{message}}h1>
<input type="text" v-model="hobby.val"/><br/><br/>
<input type="text" :value="hobby.val"/><br/><br/>
<p>你输入的爱好是: {{hobby.val}}p>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "你好, 输入你的爱好!",
hobby: {
val: "购物"
}
}
});
console.log("vm=>", vm);
script>
使用Vue的数据双向绑定, 完成
- 当用户在输入框输入1,jpg, 2.jpg, 3.jpg时可以切换显示对应的图片
- 使用Vue的数据双向绑定, 完成
<body>
<div id="app">
<h1>{{message}}h1>
<input type="text" v-model="img_src"/><br/><br/>
<img v-bind:src="img_src" v-bind:width="img_width"/><br/><br/>
<img src="1.jpg" v-bind:width="img_width"/>
<img src="2.jpg" v-bind:width="img_width"/>
<img src="3.jpg" v-bind:width="img_width"/>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "请输入图片编号 1.jpg, 2.jpg, 3.jpg!",
img_src: "1.jpg",
img_width: "400px"
}
});
console.log("vm=>", vm);
script>
body>
基本说明
- 使用 v-on 进行事件处理, 比如: v-on: click 表示处理鼠标点击事件
- 时间调用的方法定义在 vue 对象声明的methods节点中
- v-on: 事件名, 可以绑定指定事件
- 官方网站: https://v2.cn.vuejs.org/v2/guide/events.html
需求: 演示Vue事件绑定操作
<body>
<div id="app">
<h1>{{message}}h1>
<button v-on:click="sayHi()">点击输出button>
<button v-on:click="sayOk()">点击输出button>
<button v-on:click="sayHi">点击输出button>
<button @click="sayOk">点击输出button>
div>
<script src="vue.js">script>
<script>
//1.创建一个Vue实例, 并挂载到id=app的div上, el 就是element的简写
//2.这里创建的Vue实例, 可以不去接受, 也可以去接受. 接收方便我们调试信息
let vm = new Vue({
el: "#app",
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "vue事件处理的案例 ",
},
//解读:
// 1.是一个methods属性, 对应的值是对象{}
// 2.在{ }中, 可以写很多的方法, 可以理解成是一个方法池
methods: {
sayHi() {
console.log("hi, 银角大王");
},
sayOk() {
console.log("hi, 金角大王");
},
},
});
script>
body>
Vue 输入框组件 @input、@keyup.enter、@change、@blur
vm -> $el -> childNodes -> Button节点下查看
需求: 点击按钮, 次数联动变化
- 当用户 “点击增加+1” 按钮时, 次数+1
- 当用户 “点击增加+2” 按钮时, 次数+2
- 使用常规方法和表达式形式完成(两种方式都要掌握)
<body>
<div id="app">
<h1>{{message}}h1>
<button v-on:click="add">点击增加+1button>
<button @click="count += 2">点击增加+2button>
<p>你的按钮被点击了{{count}}次p>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "演示Vue事件绑定操作",
count: 0,//点击的次数
},
methods: {
add() {
//修改data数据池中的数据
//因为data和methods在同一个Vue实例中, 因此可以通过 this.数据名 来获取
//this在对象中使用, 在这里是vm实例
this.count += 1;
// vm.count += 1;
// vm._data.count += 1;
// this._data.count += 1;
// vm.$data.count += 1;
// this.$data.count += 1;
},
},
});
script>
body>
需求: 根据用户的输入, 弹窗显示内容
- 用户可以在输入框输入内容
- 点击按钮, 可以显示书名
<body>
<div id="app">
<h1>{{message}}h1>
书名: <input type="text" v-model="bookName"/>
<button v-on:click="listBook">点击显示输入框的内容button>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "演示Vue事件绑定操作",
bookName: "笑傲江湖~",
},
//解读:
// 1.是一个methods属性, 对应的值是对象{}
// 2.在{ }中, 可以写很多的方法, 可以理解成是一个方法池
methods: {
listBook() {
//this在对象中使用, this 当前对象
//this要带上, 否则报错 "ReferenceError: bookName is not defined"
alert("书名=" + bookName);
},
},
});
script>
body>
基本说明
- 修饰符(Modifiers)是以 ( . ) 指明的后缀, 指出某个指令以特殊方式绑定
- 官方文档: https://v2.cn.vuejs.org/v2/guide/events.html#事件修饰符
需求: 演示v-on:submit.prevent 的使用, 如果没有输入名字, 控制台输出 “请输入名字”, 否则输出 “提交表单”
- 为什么在开发中, 有时需要, 让某个指令以特殊方式提交, 比如表单提交
- 我们不希望这个表单进行整体提交, 而是以Ajax的方式进行提交
- 因为表单整体提交会导致重载页面, 而Ajax方式可以有选择性地提交数据, 并且可局部刷新
<body>
<div id="app">
<form action="http://www.baidu.com" v-on:submit.prevent="mySubmit">
妖怪名: <input type="text" v-model="monster.name"><br/><br/>
<button type="submit">注册button>
form>
<p>服务器回送的数据是{{count}}p>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {//数据池
monster: {//monster数据(对象)的属性, 可以动态生成
},
count: 0,
},
methods: {//方法池
mySubmit() {
// 这里不能用this.name获取
if (this.monster.name) {// "" undefined都是false
console.log("提交表单 name=", this.monster.name);
//这里, 程序员就可以根据自己的业务发出ajax请求到后端
//得到数据后,再进行数据更新-局部刷新
this.count = 1;
} else {
console.log("请输入名字");
}
},
},
});
script>
body>
为了在必要的情况下支持旧浏览器, Vue提供了绝大多数常用的按键码的别名.enter .tab .delete .esc .space .up .down .left .right
<h1>修饰符扩展案例h1>
<button v-on:click.once="onMySubmit">点击一次button><br/><br/>
<input type="text" v-on:keyup.enter="onMySubmit">
<input type="text" v-on:keyup.right="onMySubmit">
<input type="text" v-model.trim="count">
Vue提供了v-if 和 v-show 条件指令完成条件渲染/控制
官方文档: https://v2.cn.vuejs.org/v2/guide/conditional.html
v-if
指令用于条件性地渲染一块内容, 这块内容只会在指令的表达式返回true值时被渲染
细节: count是要往data数据池中找的, 如果count为true, 那么这个标题被输出; 如果在data数据池中没有找到这个变量, count返回undefined, 在js中, undefined为false, 则不会被渲染
<h1 v-if="count">helloh1>
也可以用v-else
添加一个"else"块
<h1 v-if="count">helloh1>
<h1 v-else>no h1>
应用实例
<body>
<div id="app">
<input type="checkbox" v-model="ok"/>是否同意条款[v-if实现]
<h1 v-if="ok">你同意条款h1>
<h1 v-else>你不同意条款h1>
div>
<script src="vue.js">script>
<script>
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
ok: false,
}
});
script>
body>
另一个用于根据条件展示元素的选项是v-show
指令, 用法大致一样
细节: 去data数据池中获取ok的值, 如果ok值为true, 标签被渲染; 如果ok值为false, 不会被渲染
<h1 v-show="ok">helloh1>
应用实例
<input type="checkbox" v-model="ok"/>是否同意条款[v-show实现]
<h1 v-show="ok">你同意条款h1>
<h1 v-show="!ok">你不同意条款h1>
v-if会确保在切换过程中, 条件块内的事件监听器和子组件销毁和重建
演示: 方式一
演示: 方式二 vm -> $el -> childNodes -> h1标签
v-show不管初始条件是什么, 元素总是被渲染, 并且只是对CSS进行切换
演示: 方式一
演示: 方式二
使用建议: 如果要频繁地切换, 建议使用v-show; 如果运行时条件很少改变, 使用v-if较好
需求: 当用户输入成绩时, 可以输出对应的级别
- 90分以上, 显示优秀
- 79分以上, 显示良好
- 60分以上, 显示及格
- 低于60分, 显示不及格
- 如果用户输入的成绩大于100, 就修正成100; 如果用户输入的成绩小于0, 就修正成0
Vue 输入框组件 @input、@keyup.enter、@change、@blur
<body>
<div id="app">
<h1>{{message}}h1>
输入成绩1-100: <input type="text" v-model="score" v-on:input="correct"/>
<p>你当前的成绩是 {{score}}p>
<p v-if="score >= 90">优秀p>
<p v-else-if="score >= 70">良好p>
<p v-else-if="score >= 60">及格p>
<p v-else>不及格p>
div>
<script src="vue.js">script>
<script>
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
message: "演示条件判断",
score: "",//当前的成绩
},
methods: {
correct() {
//判断成绩并修正
this.score = (this.score > 100) ? 100 : this.score;
this.score = (this.score < 0) ? "" : this.score;
},
}
});
script>
body>
基本说明
- Vue提供了 v-for 列表循环指令
官网文档: https://v2.cn.vuejs.org/v2/guide/list.html
<body>
<div id="app">
<ul>
<h1>简单的列表渲染h1>
<li v-for="i in 3">{{i}}li>
ul>
<ul>
<h1>简单的列表渲染-带索引h1>
<li v-for="(j, index) in 3">{{j}} - {{index}}li>
ul>
<h1>遍历数据列表h1>
<table border="1px" width="500px">
<tr v-for="(monster, index) in monsters">
<td>{{index}}td>
<td>{{monster.id}}td>
<td>{{monster.name}}td>
<td>{{monster.age}}td>
tr>
table>
div>
<script src="vue.js">script>
<script>
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //数据池
monsters: [
{id:1, name:"牛魔王", age:800},
{id:2, name:"齐天大圣", age:900},
{id:3, name:"红孩儿", age:200},
]
},
});
script>
body>
需求: 显示成绩及格的学生列表
- 将学生对象, 存放在数组中
- 遍历显示所有学生, 只显示成绩及格的学员
<body>
<div id="app">
<h1>{{message}}h1>
<table border="1px" width="300px">
<tr>
<td>indextd>
<td>idtd>
<td>nametd>
<td>agetd>
<td>scoretd>
tr>
<tr v-for="(student, index) in students">
<template v-if="student.score >= 60">
<td>{{index}}td>
<td>{{student.id}}td>
<td>{{student.name}}td>
<td>{{student.age}}td>
<td>{{student.score}}td>
template>
tr>
table>
div>
<script src="vue.js">script>
<script>
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //数据池
message: "学生成绩列表-及格的学生",
students: [
{id: 1, name: "jack", age: 20, score: 90},
{id: 2, name: "john", age: 19, score: 55},
{id: 3, name: "tom", age: 21, score: 42},
{id: 4, name: "mary", age: 20, score: 60}
]
},
});
script>
body>
基本说明
- 在大型应用开发的时候, 页面可以划分为很多部分, 往往不同的页面, 会有相同的部分. 例如可能会有相同的头部导航.
- 但是如果每个页面都独自开发, 这无疑增加了我们开发的成本. 所以我们会把页面的不同部分拆分成独立的组件, 然后在不同页面就可以共享这些组件, 避免重复开发
<body>
<div id="app">
<button v-on:click="click1()">点击次数= {{count}}次 [非组件化方式]button><br/><br/>
<button v-on:click="click2()">点击次数= {{count2}}次 [非组件化方式]button><br/><br/>
<button v-on:click="click3()">点击次数= {{count3}}次 [非组件化方式]button><br/><br/>
div>
<script src="vue.js">script>
<script>
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //数据池
count: 0,
count2: 0,
count3: 0,
},
methods: {//methods属性, 可以定义相应的方法
click1() {
this.count++;
},
click2() {
this.count2++;
},
click3() {
this.count3++;
},
}
});
script>
body>
<body>
<div id="app">
<h1>{{message}}h1>
<counter>counter><br/><br/>
<counter>counter>
div>
<script src="vue.js">script>
<script>
//1.定义一个全局组件, 名称为counter
//2.{} 表示我们组件相关的内容
//3.template用于指定该组件的界面, 因为会引用到数据池里的数据, 所以需要使用模板字符串
//4.这里要特别强调: 要把组件视为一个Vue实例, 也有自己的数据池和methods
//5.特别说明: 对于组件, 我们的数据池的数据是使用函数/方法返回[目的是为了保证每个组件的数据是独立的], 不能使用原来的方式
//6.这时我们就达到了, 界面通过template实现共享, 业务处理也复用
Vue.component("counter", {
template: ``,
/*data: {//错误方式 The "data" option should be a function that returns a per-instance value in component definitions.
count: 10
},*/
data() {//这里需要注意, 和原来的方式不一样!!!
return {
count: 10,
}
},
methods: {
click() {
this.count++;
},
}
})
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
data: { //数据池
message: "组件化编程-全局组件",
}
});
script>
body>
<body>
<div id="app">
<h1>{{message}}h1>
<my_counter>my_counter><br/><br/>
<my_counter>my_counter><br/><br/>
<my_counter>my_counter><br/><br/>
div>
<script src="vue.js">script>
<script>
//定义一个组件, 组件的名称为 buttonCounter
//扩展: 1.将来可以把常用的组件, 定义在某个commons.js中
// 2.如果某个页面需要使用, 直接import
const buttonCounter = {
template: ``,
data() {//这里需要注意, 和原来的方式不一样!!!
return {
count: 10,
}
},
methods: {
click() {
this.count++;
},
}
};
//为了调试方便, 用vm来接收Vue实例
let vm = new Vue({
el: "#app",//创建的vue实例挂载到id=app的div
components: {//引入某个组件, 此时my_counter就是一个组件, 它是一个局部组件, 它的适用范围就在当前的Vue实例中
"my_counter": buttonCounter,
},
data: { //数据池
message: "组件化编程-局部组件",
}
});
script>
body>
全局组件是属于所有Vue实例, 因此可以在所有Vue实例中使用
<body>
<div id="app">
<h1>组件化编程-全局组件h1>
<counter>counter><br/><br/>
<counter>counter>
div>
<div id="app2">
<h1>组件化编程-全局组件-app2h1>
<counter>counter><br/><br/>
<counter>counter>
div>
<script src="vue.js">script>
<script>
Vue.component("counter", {
template: ``,
data() {
return {
count: 10,
}
},
methods: {
click() {
this.count++;
},
}
})
let vm = new Vue({
el: "#app",
});
let vm2 = new Vue({
el: "#app2",
});
script>
body>
局部组件, 作用范围只在引入这个组件的Vue实例中
<div id="app">
<h1>组件化编程-局部组件</h1>
<my_counter></my_counter><br/><br/>
<my_counter></my_counter>
</div>
<div id="app2">
<h1>组件化编程-局部组件-app2</h1>
<zzw_counter></zzw_counter><br/><br/>
<zzw_counter></zzw_counter>
</div>
<script src="vue.js"></script>
<script>
const buttonCounter = {
template: `<button v-on:click="click()">点击次数= {{count}}次 [局部组件化]</button>`,
data() {
return {
count: 10,
}
},
methods: {
click() {
this.count++;
},
}
};
let vm = new Vue({
el: "#app",
components: {
"my_counter": buttonCounter,
},
});
let vm2 = new Vue({
el: "#app2",
components: {
"zzw_counter": buttonCounter,
},
});
</script>
</body>
基本说明
需求: 展示vue实例生命周期和钩子函数/监听函数/生命周期函数 执行时机
- 重点展示几个重要的钩子函数(beforeCreate, created, beforeMount, mounted, beforeUpdate, updated)
- 在这几个钩子函数中, 数据模型是否加载/使用?
自定义方法是否加载/使用?
html模板(页面DOM)是否加载/使用?
html模板是否完成渲染(插值表达式是否更新)?
学习小技巧/起到大作用: 自己对某个知识有疑问, 可以设计一些小案例, 来验证
Vue实例生命周期非常重要, Vue编程模型都是建立在此基础上
<body>
<div id="app">
<span id="num">{{num}}span>
<button @click="num++">点赞!button>
<h2>{{name}}, 有{{num}}次点赞h2>
div>
<script src="vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
name: "Kristina",
num: 0,
},
methods: {
show() {
return this.name;
},
add() {
this.num++;
},
},
beforeCreate() {//生命周期函数-创建Vue实例前
console.log("============beforeCreate============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [不能使用]", this.name, " ", this.num);//undefined undefined
// console.log("自定义的方法 是否加载/是否能使用? [不能使用]", this.show());//Error in beforeCreate hook: "TypeError: this.show is not a function"
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
},
created() {//生命周期函数-创建Vue实例后
console.log("============created============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
//内存模型还未编译, 外面的页面dom肯定不会被渲染
console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
//可以发出Ajax请求
//接收返回的数据
//再次更新data数据池的数据
//编译内存模板结构
//挂载
//...替换
},
beforeMount() {//生命周期函数-挂载前
console.log("============beforeMount============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
//还没有把内存编译好的模板替换到用户页面的dom结构上, 仍然看不到渲染后的结果
console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
},
mounted() {//生命周期函数-挂载后
console.log("============mounted============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
//把内存中的模板替换到el上, 即挂载点上
console.log("用户的页面dom 是否被渲染? [已经渲染]", document.getElementById("num").innerText);//0
},
beforeUpdate() {//生命周期函数-页面数据更新前
console.log("============beforeUpdate============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
console.log("用户的页面dom 是否被更新? [未被更新]", document.getElementById("num").innerText);//0
//验证前如果数据有错误, 需要修正数据
//举个例子
// if (this.num < 10) {
// this.num = 10;
// }
},
updated() {//生命周期函数-页面数据更新后
console.log("============updated============");
console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
console.log("用户的页面dom 是否被更新? [已经更新]", document.getElementById("num").innerText);//1
},
})
script>
body>
回答一: 创建前-创建后-挂载前-挂载后-销毁前-销毁后
回答二: 创建前, 初始化事件和生命周期; 创建后, 加载数据池数据和方法池自定义方法; 挂载前, 编译内存模板, 形成内存模板结构; 挂载后, 页面已被渲染, 可以看到最新数据; 更新前, 已监听到数据池数据变化, 数据池变化有可能是前端传来的数据[双向绑定], 或者是点击某个按钮, 导致数据池数据变化, 也有可能是后端传来的数据导致数据池数据变化; 更新后, 会重新渲染内存模板结构(修补一下内存模板, 类似于打补丁,把修补好的内存模板替换到页面上), 并把渲染好的模板结构, 替换至页面上(); 销毁前, 数据和方法还能访问; 销毁后, 数据和方法已不能再访问.
回答三: 在new一个Vue实例后, 会执行Init Events & lifecycle
, Vue底层来做的, 无法干预. 即初始化事件和生命周期. 这时, 在beforeCreate()函数中, 数据池中的数据和方法池中自定义的方法还未被加载, 但div模板已加载, 前端页面还拿不到数据池中的数据. 接下来, 会进行Init injections & reactivity
, 即会注入数据, 会加载/初始化数据池和方法池中自定义的方法, 在create()函数中, 会拿到数据池中的数据和方法池中自定义的方法, 但这时前端界面仍然拿不到数据.接下来, 会判断有无$el, 有无template, 会在内存中形成一个模板, 即内存模板结构, 此时还未把内存模板挂载到div上, 所有前端页面仍然拿不到数据. 在beforeMount()函数执行之前, 即在挂载之前, 内存模板已经编译好, 之后会进行挂载Compile template into render function *
, 这时内存模板已经挂载到页面dom上, 在挂载之后执行的mounted()函数中, 已经可以看到最新渲染过后的页面. 当页面拿到数据后, 程序会监听数据池中的数据变化 (数据池变化有可能是前端传来的数据[双向绑定],或者是点击某个按钮导致数据池数据变化, 也有可能是后端传来的数据导致数据池数据变化), 当监听到数据变化时, 会触发生命周期函数beforeUpdate, 这时函数内已经可以拿到数据池新的数据, 但是这数据还未更新到页面DOM上, 页面上还是显示的上一次的数据. 之后会进行Virtual DOM re-render and patch
, 会进行重新渲染和打补丁( 会重新渲染内存模板结构,[修补一下内存模板, 类似于打补丁, 把修补好的内存模板替换到页面上] 并把渲染好的模板结构, 替换至页面上. ). 这时, 之后执行的updated()函数中, 已经可以看到页面上最新的数据. 最后, 在Vue实例即将销毁时, 即when vm.$destroy() is called
, 在销毁方法即将被调用时, 会执行一个beforeDestroy()函数, 这时, 数据池中的数据和方法池中自定义的方法还能使用, 之后会进行注销组件和事件监听器的操作. 最后, 在destroyed()方法中, 已经拿不到数据. 最后进行销毁.
Vue Cli 是一个基于Vue.js进行快速开发的完整系统
官网文档: https://cli.vuejs.org/zh/
目前开发模式的问题
- 开发效率低
- 不够规范
- 维护和升级, 可读性差
需求: 使用Vue脚手架进行模块化开发, 输入不同的url, 切换不同页面
说明: npm 和 cnpm 的区别
- 两者之间只是node中包管理器的不同, 都可以使用
- npm是node官方的包管理器. cnpm是个中国版的npm, 是淘宝定制的 cnpm (gzip压缩支持)命令行工具, 代理默认的npm
- 如果因为网络原因无法使用npm下载, 那么这个cnpm就派上用场了
- 小结: npm和cnpm只是下载的地址不同, npm是从国外下载东西, cnpm是从国内下载东西
可能会报的错误
成功. 如果端口占用, vue会默认切换到另一个端口
如果报告端口占用的错误, 就把端口让出来, 重新运行命令
输入Ctrl + C 终止程序
Vue请求页面执行流程
当我们输入http://localhost:8080, 看到的页面从何而来
因为Vue默认生成的代码, 使用了很多简写, 造成了初学者理解困难.
整个页面渲染过程中, main.js是中心, 也是连接各个组件, 路由器的关键.
题目一: 输入http://localhost:8080/#/hello, 返回
配置自己的组件 HelloMary.vue
<template>
<div>
<h1>{{ msg }}h1>
div>
template>
<script>
export default {
name: "HelloMary",
data() {//数据池
return {
msg: "HelloMary"
}
}
}
script>
配置路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld.vue'
//@指的是src目录
import HelloMary from "@/components/HelloMary.vue"
import Zzw from "@/components/Zzw.vue"
Vue.use(Router)
export default new Router({
routes: [ //路由表
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{//配置的一组路由
path: '/hello',
name: 'HelloMary',
component: HelloMary
}
]
})
题目二: 输入http://localhost:8080/#/
配置自己的组件 Zzw.vue
<template>
<div>
<h1>{{ msg }}h1>
<table>
<tr>
<td colspan="3">第1行第1列td>
tr>
<tr>
<td rowspan="2">第2行第1列td>
<td>第2行第2列td>
<td>第2行第3列td>
tr>
<tr>
<td>第3行第2列td>
<td>第3行第3列td>
tr>
<tr>
<td rowspan="2">第4行第1列td>
<td>第4行第2列td>
<td>第4行第3列td>
tr>
<tr>
<td>小猫咪<img src="@/assets/1.gif" width="100">td>
<td>第5行第3列td>
tr>
table>
div>
template>
<script>
export default {
name: "Zzw",
data() {
return {
msg: "Welcome to Zzw!"
}
},
}
script>
<style scoped>
div {
background-color: beige;
width: 600px;
margin: 0 auto;
}
table, td {
border: solid red 1px;
width: 600px;
height: 50px;
border-collapse: collapse; /*边界合并*/
}
h1 {
color: red;
}
style>
配置路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld.vue'
//@指的是src目录
import HelloMary from "@/components/HelloMary.vue"
import Zzw from "@/components/Zzw.vue"
Vue.use(Router)
export default new Router({
routes: [ //路由表
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/hello',
name: 'HelloMary',
component: HelloMary
},
{//配置的一组路由
path: "/zzw",
name: "Zzw",
component: Zzw
}
]
})
App.vue 项目主体单页
<template>
<div id="app">
<router-view/>
div>
template>
<script>
export default {
name: 'App'
}
script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
style>
HelloMary.vue
<template>
<div>
<img src="@/assets/logo.png"/>
<h1>{{ msg }}h1>
div>
template>
<script>
export default {
name: "HelloMary",
data() {//数据池
return {
msg: "HelloMary"
}
}
}
script>
<style scoped>
style>
HelloWorld.vue
<template>
<div class="hello">
<img src="@/assets/logo.png"/>
<h1>{{ msg1 }}h1>
<h2>{{ msg2 }}h2>
<a href="https://www.baidu.com" target="_blank">{{ msg3 }}a>
div>
template>
<script>
export default {//默认导出组件
name: 'HelloWorld',
data () {//数据池
return {
msg1: '网站首页-赵志伟',
msg2: '网站首页-赵志伟',
msg3: '点击进入百度'
}
}
}
script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
style>
基本说明
- ElementUI官网: https://element.eleme.cn/#/zh-CN
vue2对应ElementUI.
vue3对应ElementPlus- ElementUI是组件库, 是网站快速成型的工具
在Vue2项目中, 使用ElementUI组件. Vue3使用ElementPlus
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
如果自己的代码里有data数据池, methods, template, 那么只需引入data里的数据, methods里的方法和template里的代码即可
axios底层地址是promise promise讲解
基本说明
学习文档: https://javasoho.com/axios/
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="vue.js"></script>
<script src="axios.min.js"></script>
需求: 在Vue项目中使用Axios, 从服务器获取json数据, 显示在页面
创建一个JavaScript项目
data/response.data.json
{
"success": true,
"message": "成功",
"data": {
"items": [
{
"name": "牛魔王",
"age": 900
},
{
"name": "红孩儿",
"age": 400
},
{
"name": "齐天大圣",
"age": 890
},
{
"name": "唐玄奘",
"age": 80000
}
]
}
}
把vue.js库文件 和 axios.min.js库文件 拷贝到项目路径下
请求url在浏览器地址栏copy一下
<body>
<div id="app">
<h1>{{msg}}h1>
<table border="1px" width="300px">
<tr>
<td>名字td>
<td>年龄td>
tr>
<tr v-for="monster in monsterList">
<td>{{monster.name}}td>
<td>{{monster.age}}td>
tr>
table>
div>
<script src="vue.js">script>
<script src="axios.min.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "妖怪信息列表",
monsterList: [],//表示妖怪的信息数组
},
methods: {//定义方法
list() {//发出ajax请求, 获取数据 axios
/*
解读
1. axios.get() 表示发出ajax请求
2. http://localhost:63342/axios/data/response.data.json 表示请求的是url
要根据实际情况来填写
3. axios发出ajax请求的基本语法
axios.get(url).then(箭头函数).then(箭头函数)...catch(箭头函数)
(1)如果get请求成功就进入第一个then()
(2)可以在 第一个then()中处理成功回调的数据, 还可以继续发出axios的ajax请求
(3)如果有异常, 会进入到 catch(箭头函数)
4. list方法在生命周期函数created() 中调用
*/
axios.get("http://localhost:63342/axios/data/response.data.json")
.then((responseData) => {
//要想准确拿到数据, 要一次一次的console.log()取
// console.log("responseData=", responseData);
// console.log("responseData.data=", responseData.data);
// console.log("responseData.data.data=", responseData.data.data);
console.log("responseData.data.data.items=", responseData.data.data.items);
//将妖怪列表数组信息, 绑定到data数据池的monsterList
//小技巧, 一定要学会看返回的数据格式
this.monsterList = responseData.data.data.items;
//可以再次发出ajax请求, 故意发出了第二次ajax请求
// return axios.get("http://localhost:63342/axios/data/response.data.json");
})
// .then(responseData => {
// console.log("第二次ajax请求返回的数据 responseData.data.data.items=", responseData);
// })
.catch(err => {
console.log("异常=", err);
});
},
},
created() {//生命周期函数
this.list();
},
})
script>
body>
将JSON对象转成字符串, 通过JSON.stringify(responseData)
格式化输出JSON字符串, 方便观察分析
//使用JSON.stringify(json), 把json对象转成字符串, 方便观察
console.log("responseData=", JSON.stringify(responseData));