MVVM(Model-View-ViewModel)是一种软件架构模式,是一种简化用户界面的事件驱动编程方式。
MVVM源自于经典的MVC(Model-View-Controller)模式,MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下
当下流行的MVVM框架有Vue.js、Angular.js。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model)
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 脚手架创建 -->
npm install @vue/cli -g
<!-- 创建项目 -->
vue create app
<div id='app'>
{{ message }}
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app', //绑定元素的ID
data: { //数据对象
message: 'Hello Vue!'
}
})
script>
概念:
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
作用:
Vue生命周期中有多个事件钩子,让我们在控制整个Vue实例过程时更容易形成好的逻辑。
阶段:
可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/后。
概念:
钩子函数,其实就是Vue提前定义好的时间,其作用类似与Servlet中的init和distory方法
语法:
<script type="text/javascript">
var app = new Vue({
el:"#app",
//钩子函数created,该方法在页面显示之后,自动执行
created() {
console.log("created...");
}
});
script>
概述:
插值表达式用户把Vue中所定义的数据,显示在页面中,插值表达式允许用户输入"JS代码片段"
语法:
{{ 变量名/对象.属性名 }}
案例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue插值表达式title>
<script src="node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="app">
<h1>欢迎来到-->{{ name }}h1>
div>
<script type="text/javascript">
//创建vue对象
var app = new Vue({
//让vue接管div标签
el:"#app",
//定义数据,里边包含一个属性name,值为"白大锅"
data:{
name:"白大锅"
}
});
script>
body>
html>
概述:
v-text和v-html专门用来展示数据,其作用和插值表达式类似。v-text和v-html可以避免插值闪烁。
插值闪烁:在数据未加载完成时,页面会显示原始的{{}},过一会才显示正常数据。
语法:
v-text:<span v-text="msg">span>{msg}} -->
v-html:<span v-html="msg">span>{msg}} -->
区别:
概述:
案例:
<div id="app">
<button @click="show = !show">点我button>
<h1 v-if="show">Hello v-if.h1>
<h1 v-show="show">Hello v-show.h1>
div>
<script>
var app = new Vue({
el:"#app",
data: {
show:true
}
});
script>
概述:
Vue中也可以给页面元素绑定事件
语法:
<button v-on:事件名="函数名/vue表达式">点我button>
<button @事件名="函数名/vue表达式">点我button>
注意:
Vue支持html中所有已知事件,如:@click,@submit等,只不过事件的名称不带on
案例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue事件处理title>
<script src="node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="app">
<button @click="show">点我button>
div>
<script type="text/javascript">
//创建vue对象
var app = new Vue({
//获取id为app的元素,该元素被vue对象所管理.只有被vue对象管理的标签,其内部才允许书写vue语法
el:"#app",
//定义vue的方法
methods:{
//定义show方法,弹出提示框
show() {
alert("Hello Vue!!!");
}
}
});
script>
body>
html>
事件修饰符:
事件修饰符主要对事件的发生范围进行限定
语法:
<button @事件名.事件修饰符="函数名/vue表达式">点我button>
事件修饰符:
.stop :阻止事件冒泡, 也就是当前元素发生事件,但当前元素的父元素不发生该事件
.prevent :阻止默认事件发生
.capture :使用事件捕获模式, 主动获取子元素发生事件, 把获取到的事件当自己的事件执行
.self :只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
.once :只执行一次
语法:
v-for="item in items"
v-for="(item,index) in items"
items:要遍历的数组
item:存储数组元素的变量名
index:迭代到的当前元素索引,从0开始
代码:
<div id="app">
<ul>
<li v-for="(user, index) in users">
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
li>
ul>
div>
<script>
var app = new Vue({
el:"#app",//el即element,要渲染的页面元素
data: {
users:[
{"name":"白卓冉","age":8,"gender":"男"},
{"name":"白大锅","age":12,"gender":"女"},
{"name":"白仙女","age":4,"gender":"男"}
]
}
});
script>
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
<div id="app">
<ul>
<li v-for="(value,key,index) in person">
{{index}}--{{key}}--{{value}}
li>
ul>
div>
<script>
var app = new Vue({
el:"#app",//el即element,要渲染的页面元素
data: {
person:{"name":"白大锅", "age":3, "address":"中国"}
}
});
script>
概述:
:key一般配合v-for一起使用,用在特定的情况下,保证被遍历数组中的元素的顺序
案例:
<div id="app">
<button @click="add">添加button>
<ul>
<li v-for="name in list">
<input type="checkbox"> {{name}}
li>
ul>
div>
<script>
var app = new Vue({
el: '#app',
data: {
list: ["孙悟空", "猪八戒", "沙和尚"]
},
methods: {
add() {
//注意这里是unshift,向数组的头部添加一个元素
this.list.unshift("唐僧");
}
}
});
script>
点击添加后
解决方案:
<div id="app">
<button @click="add">添加button>
<ul>
<li v-for="name in list" :key="name">
<input type="checkbox"> {{name}}
li>
ul>
div>
概述:
语法:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据绑定title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
单向数据绑定:<input type="text" v-bind:value="name"><br>
双向数据绑定:<input type="text" v-model:value="name">
div>
<script>
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
name:'JOJO'
}
})
script>
body>
html>
注意:
概述:
计算属性就是一个提前定义好的方法, 该方法可以看作是一个特殊的值, 可以在插值表达式中使用
语法:
var app = new Vue({
el:"#app",
//计算属性必须放在Vue的computed中
computed:{
//定义计算属性
属性名(){
return "返回值";
}
}
});
案例:
<div id="app">
<h1>{{birth}}h1>
<h1 v-text="birth">h1>
<h1 v-html="birth">h1>
div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
computed:{
//定义一个birth方法,该方法就是一个计算属性,可以在插值表达式中使用
birth(){
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth()+1;
let day = date.getDay();
return year + "-" + month + "-" + day;
}
}
});
script>
概述:
语法:
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
message:"白大锅",
person:{"name":"heima", "age":13}
},
//watch监听
watch:{
//监听message属性值,newValue代表新值,oldValue代表旧值
message(newValue, oldValue){
console.log("新值:" + newValue + ";旧值:" + oldValue);
},
//监控person对象的值,对象的监控只能获取新值
person: {
//开启深度监控;监控对象中的属性值变化
deep: true,
//获取到对象的最新属性数据(obj代表新对象)
handler(obj){
console.log("name = " + obj.name + "; age=" + obj.age);
}
}
}
});
script>
概念:
将父组件利用 插槽 将结构
传送到子组件中
插槽的本质:
是组件标签中间传递结构,实现公共代码的提取
语法:
//父组件
<子 组件名>
//传输 结构/数据
<p>数据p>
子 组件名>
//子组件
<slot>接收结构/数据slot>
案例:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue插槽title>
head>
<body>
<div id="el">
<my-div>
<my-title slot="my-title" :title="tle">my-title>
<my-item slot="my-item" v-for="(item,index) in list" :item="item" :index="index">my-item>
my-div>
div>
<script src=" https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">script>
<script>
Vue.component("my-div", {
template: `
`
});
Vue.component('my-title', {
props: ['title'],
template: `{{title}}`
});
Vue.component("my-item", {
props: ["item", "index"],
template: "- {{index+1}},{{item}}
"
});
var vm = new Vue({
el: "#el",
data() {
return {
tle: "前端基础课程",
list: ['HTML', 'CSS', 'JavaScript']
}
}
})
script>
body>
html>
图解:
概述:
组件类似于模板,模块。在项目需要重用某个模块(头部、尾部、导航…)的时候,可以将模块抽取成组件,其他页面中注册组件并引用。
案例:
<div id="app">
<counter>counter>
<counter>counter>
div>
<script type="text/javascript">
//定义组件
const counterTemp = {
//定义组件的模版
template:``,
//定义组件中使用到的数据属性
data(){
return {
num:0
}
}
};
//全局注册组件:在所有的vue实例中都可以使用组件
//参数1:组件名称,参数2:具体的组件
//Vue.component("counter", counterTemp);
var app = new Vue({
el:"#app",
//局部注册组件: 只能在当前Vue实例中使用
components:{
//组件名称:具体组件
counter: counterTemp
}
});
script>
注意:
概述:
子组件无法直接使用父组件中的数据, 如果需要使用, 则必须由父组件把数据传递给子组件才可以
本质:
让子组件中的属性与父组件中的属性进行关联绑定, 然后子组件使用该属性, 这样才能做到数据传递
意义:
可以把父组件中的数据, 更新传递到子组件
示例:
<div id="app">
<aaa :number="count" :ids="arr" :person="p">aaa>
div>
<script>
var aaa = {
//定义组件的模版
template: `{{num}}---{{number}}--{{ids}}--{{person}}
`,
//定义组件中使用到的数据属性
data() {
return {
num: 0
}
},
//给组件添加属性
props: {
//普通属性number
number: "",
//数组属性ids
ids: [],
//对象属性person
person: {}
/*
* //以上属性还可以书写为以下格式
* items:{
* //数据类型,如果是数组则是Array,如果是对象则是Object
* type:Array,
* //默认值
* default:[]
* }
*/
}
};
//注册:全局注册
Vue.component("aaa", aaa);
var app = new Vue({
el: "#app",
data: {
count: 5,
arr: [1, 2, 3],
p: {username: "zhangsan", age: 23}
}
});
script>
概述:
子组件无法直接给父组件传递数据. 也无法操作父组件中的数据, 更无法调用父组件中的方法。所以, 所谓的子组件向父组件通讯, 其实就是想办法让子组件调用父组件的方法. 进而响应到父组件中的数据。
意义:
子组件可以调用父组件中的方法
示例:
<div id="app">
<h1>父组件中:app_num={{app_num}}h1>
<counter @aaa="add" @bbb="rem" :counter_num="app_num">counter>
div>
<script>
//定义一个组件(模版)
let counter = {
template: `
子组件中:counter_num={{counter_num}}
`,
props:{
//定义属性counter_num,用来接收父组件传递的数据
counter_num:null,
//定义aaa属性,用来绑定父组件的方法,当然,该定义也可以省略
aaa:function(){},
//定义bbb属性,用来绑定父组件的方法,当然,该定义也可以省略
bbb:function(){},
},
methods:{
fun1(){
//找到aaa属性所绑定的那个方法,执行那个方法
return this.$emit("aaa");
},
fun2(){
//找到bbb属性所绑定的那个方法,执行那个方法
return this.$emit("bbb");
}
}
}
var app = new Vue({
el: '#app',
data: {
app_num: 0
},
components: {
counter
},
methods:{
add(){
this.app_num++;
},
rem(){
this.app_num--;
}
}
});
script>
概述:
axios是一个基于promise的HTTP库,主要用于:发送异步请求获取数据
常见的方法:
axios(config)
axios.get(url,[config])
axios.post(url,[data])
发送数据config常用参数:
{
url: '请求的服务器',
method: '请求方式', // 默认是 get
// GET请求参数
params: {
参数名: 参数值
},
// POST请求参数, 如果使用axios.post,则参数在url之后直接书写,不需要该位置传递参数
data: {
参数名: 参数值
},
// 响应数据格式,默认json
responseType: 'json'
}
响应数据常用参数:
{
data: {}, //真正的响应数据(响应体)
status: 200, //响应状态码
statusText: 'OK', //响应状态描述
headers: {}, //响应头
config: {} //其他配置信息
}
var app = new Vue({
el: "#app",
data: {
user: {}
},
//当页面加载完毕后
created() {
//发送GET请求axios.get("请求路径",{ config });
axios.get("请求路径",{
//get请求参数
params: {
name:"zhangsan",
age:23
},
//响应数据格式为"json"
responseType: 'json'
}).then(res => {
//打印响应数据
console.log(res);
//把响应数据赋值给Vue中的user属性
app.user = res.data;
}).catch(err => {
//打印响应数据(错误信息)
console.log(err);
});
}
});
var app = new Vue({
el: "#app",
data: {
user: {}
},
//当页面加载完毕后
created() {
//发送POST请求axios.post("请求路径",{ 参数 });
axios.post("请求路径",{
name:"zhangsan",
age:23
}).then(res => {
console.log(res);
app.user = res.data;
}).catch(err => {
console.log(err);
});
}
});
跨域请求:在前端js中如果发送异步请求的话,请求的地址与当前服务器的ip或者端口号不同都是跨域请求.