心想着虽然自己不搞前端,但是一般的前端代码自己总得看得懂吧,那国内目前比较火的前端框架,那肯定是vue了,就花一天时间来学习一下吧,就当入个门,至少以后看到代码至少懂一些基础的东西。
一、环境安装
坑还是比较多的,安装了很久,各种问题,参考这个博客,少走弯路:https://blog.csdn.net/qq_41340666/article/details/124168806
目录参考:
二、快速上手
1. 定义属性
首先通过new Vue()来创建Vue实例,然后构造函数接收一个对象,对象中有一些属性:
-
el:是element的缩写,通过id选中要渲染的页面元素,本例中是一个div
-
data:数据,数据是一个对象,里面有很多属性,都可以渲染到视图中
-
name:这里我们指定了一个name属性
-
页面中的h2元素中,我们通过{{name)}的方式,来渲染刚刚定义的name属性。
-
<template> <div class="hello"> <h3>Vue基础</h3> <p>{{ message }}</p> <div>{{rawHtml}}</div> <div v-html="rawHtml"></div> <div v-bind:id="dynamicId"></div> <p>{{num+10}}</p> <p>{{flag?"孙猴子":"傻猴子"}}</p> </div> </template> <script> export default { name: 'HelloWorld', data(){ return { message:"测试Vue学习", rawHtml:"<a href='https://www.itbaizhan.com/'>百战</a>", dynamicId:10001, num:10, flag:true } } } </script>
2. Vue生命周期(钩子)
每个Vue实例在被创建时都要经过一系列的初始化过程︰
创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。
每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。
1、生命周期:
2、渲染数据:钩子函数
例如: created代表在vue实例创建后;
我们可以在Vue中定义一个created函数,代表这个时期的构造函数;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
this.name = "虎哥";
}
});
</script>
</body>
</html>
模拟实际渲染数据:this 我们可以看下在vue内部的this变量是谁,我们在created的时候,打印this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="handleClick">点我</button><br>
<input type="text" v-model="num" /><button @click="num++">+</button>
<h1>
{{name}} xxx非常美丽!<br>
{{num}} 位其着迷!
</h1>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
name:"",
num: 1,
},
methods : {
handleClick(){
console.log(this)
console.log("hello");
}
},
created(){
//向后台发起Ajax请求,完成对data数据初始化
setTimeout(() => this.name = "虎哥 真的",1000)
}
});
</script>
</body>
</html>
总结: this就是当前的Vue实例,在Vue对象内部,必须使用this才能访问到Vue中定义的data内属性、方法等。
3. 指令
什么是指令?
指令(Directives)是带有 v-前缀的特殊属性。
例如我们在入门案例中的v-model,代表双向绑定。
1、插值表达式
(1)花括号
格式:{{表达式}}
说明;
- 该表达式支持JS语法,可以调用js内置函数(必须有返回值)
- 表达式必须有返回结果。例如1+1,没有结果的表达式不允许使用,如: var a = 1+1;
- 可以直接获取Vue实例中定义的数据或函数
示例
HTML:<div id= " app">i{name ) )</div>
JS:
var app =new vue({
el:"#app",
data:{
name:"Jack""
}
})
2、差值闪烁
使用0方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的
加载完毕后才显示正确数据,我们称为插值闪烁。
我们将网速调慢一些,然后试试看刚才的案例:发现刷新页面有延迟
3、使用v-text和v-html
使用v-text
和v-html
指令来替代{{}}说明:
v-text
∶将数据输出到元素内部,如果输出的数据有代码,会作为普通文本输出
v-html
:将数据输出到元素内部,如果输出的数据有HTML代码,会被渲染
4、v-model
刚才的v-text和v-html可以看做是单向绑定,数据影响了视图渲染,但是反过来就不行。
接下来学习的v-model是双向绑定,视图(view)和模型(Model)之间会互相影响。
既然是双向绑定,一定是在视图中可以修改数据,这样就限定了视图的元素类型。
目前v-model的可使用元素有:input、select、textarea、checkbox、radio、components(Vue中的自定义组件)
5、v-on
(1)基本用法
v-on指令用于给页面元素绑定事件。
语法:v-on:事件名="js片段或函数名"
简写语法:例如v-on:click='add'
可以简写为@click='add'
<template>
<div class="hello">
<!-- <button v-on:click="counter += 1">点击:counter = {{counter}}</button> -->
<button @:click="counter += 1">点击:counter = {{counter}}</button>
<button @:click="clickHandle">按钮</button>
<p>{{ message }}</p>
<button @click="say('hi')">say hi</button>
<button @click="say('what')">say what</button>
<ul>
<li @click="clickItemHandle(item)" v-for="(item,index) in names" :key="index">
{{item}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
counter:1,
message:"消息通知",
names:["iwen","ime","frank"]
}
},
methods:{
clickHandle(event){
// console.log("哈哈哈");
//在事件中,读取data中的属性,是需要通过this.属性来实现的
this.message = "消息被撤回了";
//event是原生DOM event
console.log(event);
event.target.innerHTML = "点击之后"
},
say(data){
console.log(data);
},
clickItemHandle(item){
console.log(item);
}
}
}
</script>
(2)点击事件(包含关系(冒泡))
(3)点击事件(设置不自动包含关系(停止冒泡))
(4)事件修饰符
在事件处理程序中调用event.preventDefault()或event.stopPropagation())是非常常见的需求。
尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。
为了解决这个问题,Vue.js 为v-on提供了事件修饰符。
之前提过,修饰符是由点开头的指令后缀来表示的
- stop ︰阻止事件冒泡
- prevent :阻止默认事件发生
- capture :使用事件捕获模式
- self∶只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
- once:只执行一次
(5) 阻止默认事件发生 阻止a标签跳转
6、v-for
遍历数据渲染页面是非常常用的需求,Vue中通过v-for指令来实现。
(1)遍历数组
语法:v-for="item in items ""
-
items:要遍历的数组,需要在vue的data中定义好。
-
item:迭代得到的数组元素的别名
-
<template> <div class="hello"> <h3>列表渲染</h3> <ul> <li v-for="item in newsList"> {{ item.title }} </li> </ul> </div> </template> <script> export default { name: 'HelloWorld', data(){ return { newsList:[ { id:1001, title:"今日新闻1" }, { id:1002, title:"今日新闻2" }, { id:1003, title:"今日新闻3" } ] } } } </script>
(2)遍历数组:多个参数(数组角标)
在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数:
语法:v-for=" (item, index) in items "
- items:要迭代的数组
- item:迭代得到的数组元素别名
- index:迭代到的当前元素索引,从0开始
7、key
当Vue.js用v-for 正在更新已渲染过的元素列表时,它默认用"就地复用"策略。
如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这个功能可以有效的提高渲染的效率。
但是要实现这个功能,你需要给Vue一些提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素
你
需要为每项提供一个唯一 key属性。理想的key值是每项都有的且唯一的id。
提升加载数据的速度
8、v-if和v-show
v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
语法:v-if”布尔表达式”
9、v-if与v-for结合以及v-else
(1)v-if
当v-if和v-for出现在一起时,v-for优先级更高。也就是说,会先遍历,再判断条件。
<template>
<div class="hello">
<p v-if="flag"> 我是程哥哥 </p>
<p v-else> 我不是程哥哥 </p>
<p v-show="flag"> 真的是程哥哥呀 </p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
flag:false
}
}
}
</script>
(2)v-else
(3)v-if和v-show的区别(面试常问)
10、v-bind
(1)创建新的HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
}
});
</script>
</body>
</html>
(2)编写CSS样式和HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<button>红色</button>
<button>蓝色</button>
<div id="box" class="red">
我是盒子
我是盒子
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
}
});
</script>
</body>
</html>
(3)添加点击切换图片的事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
div #box{
width:100px;
height: 100px;
color: darkgray;
}
.red{
background-color: red;
}
.blue{
background-color: blue;
}
</style>
</head>
<body>
<div id="app">
<button @click="color='red'">红色</button>
<button @click="color='blue'">蓝色</button>
<div id="box" class="{{color}}">
我是盒子
我是盒子
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",//elemnet,vue 作用的标签
data:{
color:"red",
}
});
</script>
</body>
</html>
11、计算属性
在插值表达式中使用js表达式是非常方便的,而且也经常被用到。
但是如果表达式的内容很长,就会显得不够优雅,而且后期维护起来也不方便
12、单表输入绑定
form表单输入值获取
<template>
<div class="hello">
<input type="text" v-model="username">
<p>{{username}}</p>
<button @click="clickGetUserName">获取用户名</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
username:""
}
},
methods:{
clickGetUserName(){
console.log(this.username);
}
}
}
</script>
13、watch
(1)监控
watch可以让我们监控一个值的变化,从而做出相应的反应。
(2)浅监控
(3)深监控,监控对象
4. 组件化
在大型应用开发的时候,页面可以划分成很多部分。
往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。
但是如果每个页面都独白开发,这无骚增加了我们开发的成本。
所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
1、定义安全组件
我们通过Vue的component方法来定义一个全局组件。
2、组件的复用
定义好的组件,可以任意复用多次:
3、局部注册
一旦局部注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。
因此,对于一些并不频繁使用的组件,我们会采用局部注册。
我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
<template>
<h3>我是单文件组件</h3>
</template>
<script>
export default{
name:"MyComponent"
}
</script>
<style>
h3{
color: red;
}
</style>
4、组件通信
通常一个单页应用会以一棵嵌套的组件树的形式来组织:
- 页面首先分成了顶部导航,左侧内容区,
- 左侧内容区又分为上下两个组件
- 右侧边栏中又包含了3个子组件
各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。
(1)父向子传递:props
比如我们有一个子组件:
Vue.component("introduce",{
// 直接使用props接收到的属性来渲染页面
template:'<h3>{{title}}</h3>',
props:[title] // 通过props来接收一个父组件传递的属性
})
-
这个子组件中要使用title属性渲染页面,但是自己并没有title属性
-
通过props来接收父组件属性,名为title
-
<template> <h3>prop传递数据</h3> <p>{{title}}</p> <p>age={{age}}</p> <p>{{names}}</p> <ul> <li v-for="(item,index) in names" :key="index">{{item}}</li> </ul> </template> <script> export default{ name:"PropComponent", props:{ title:{ type:String, default:"" }, age:{ type:Number, default:0 }, names:{ type:Array, //数组和对象必须使用函数来返回 default:function(){ return [] } } } } </script> <style scoped> </style>
(2)子向父通信
-
子组件接收父组件的num属性
-
子组件定义点击按钮,点击后对num进行加或减操作
-
vue提供了一个内置的this.$emit函数,用来调用父组件绑定的函数
-
<template> <h3>自定义事件传递数据</h3> <button @click="sendClickHandle">点击传递</button> </template> <script> export default{ name:"ZidingyiComponent", data(){ return{ message:"我是ZidingyiComponent" } }, methods:{ sendClickHandle(){ //参数一:字符串 //参数二:传递的数据 this.$emit("onEvent",this.message); } } } </script> <style scoped> </style>
-
<template> <img alt="Vue logo" src="./assets/logo.png"> <ZidingyiComponent @onEvent="getDataHandle"/> <p>{{message}}</p> </template> <script> import ZidingyiComponent from './components/ZidingyiComponent.vue'; export default { name: 'App', data(){ return { message:"" } }, components: { ZidingyiComponent }, methods:{ getDataHandle(data){ console.log(data); this.message=data; } } } </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>
5. Axios请求
1. axios发送网络请求
<template>
<div class="hello">
<p>{{chengping}}</p>
</div>
</template>
<script>
import axios from "axios"
export default {
name: 'HelloWorld',
data(){
return{
chengping:{}
}
},
mounted(){
axios({
method:"get",//or post
url:"www.baidu.com"
}).then(res=>{
console.log(res.data);
this.chengping=res.data;
})
}
}
</script>
2. axios网络请求封装
import axios from "axios"
import { config } from "process";
import querystring from "querystring"
const instance = axios.create({
//网络请求公共配置
timeout:5000
})
//拦截器最常用
//发送数据
instance.interceptors.request.use(
config=>{
if(config.methods==="post"){
config.data = querystring.stringify(config.data)
}
//config:包含网络请求的所有信息
return config;
},
error=>{
return Promise.reject(error)
}
)
//获取数据之前
instance.interceptors.response.use(
response=>{
return response.status === 200?Promise.resolve(response):Promise.reject(error);
},
error=>{
const { response } = error;
//错误的处理才是我们最应该关注的
errprHandle(response.status,response.info);
}
)
export default instance;
6. 路由配置
https://router.vuejs.org/zh/