前言:大家好,这次给大家带来一门vue2的基础教程,内容是vued的基本指令,侦听器,过滤器,计算属性,组件的注册,通信,插槽,生命周期,vue-cli快速搭建项目,axios,Vue Router ,Vuex。配套视频一起讲解。
1.vue是什么,这门课可以收获什么?
Vue目前是前端非常火的一个框架,本课程带大家快速掌握vue2的知识点,可以快速上手项目开发。
2.环境搭建
Nodejs下载:https://nodejs.org/en/download,不建议使用最新的,不太稳定,安装好以后,win + r,输入cmd,在黑窗口输入node -v,看到对应的版本信息就是安装成功了。其中npm是nodejs的包管理工具。
在黑窗口输入该命令,提高获取速度:npm config set registry https://registry.npm.taobao.org
查看是否成功:npm config get registry
vscode软件作为开发软件,下载很简单,一路默认就好了,安装完成需要下载一些插件方便开发,如图:
还有一个webpack构建工具,就是快速构建项目的,这里大家做一个了解就好。
3.vue-cli搭建项目
npm install -g @vue/cli
vue create my-project
4.基本指令的讲解
模板语法,v-text和v-html,v-if和v-show,v-bind,v-on,v-for,v-model
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<h1>{{ message }}</h1>
<h1 v-text="title"></h1>
<h1 v-html="title"></h1>
<h1 :class="meaage"></h1>
<input type='text' v-model="count"/>
<button @click="add">加1</button>
<h1 v-ifshow="flag">成功</h1>
<h1 v-if="flag">成功</h1>
<h1 v-else>失败</h1>
<ul v-for="(item,index) in books" :key="index">
<li>{{ item }} {{ index }}</li>
</ul>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'HomeView',
components: {
},
data(){
return{
count:100,
name:'helloworld',
title:"<h1>helloworld</h1>",
flag:true,
books:['java','vue','python']
}
},
methods:{
add(){
this.count++;
}
},
watch:{
},
computed:{
},
filters:{
//处理函数
addPriceIcon(value){
console.log(value)
return '¥' + value
}
}
}
</script>
<style scoped>
</style>
5.侦听器,过滤器,计算属性
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<div style="border:1px solid red">
<h1>侦听器:侦听器本质上是一个函数,如果要监听哪一个数据的变化,就把那个数据作为函数名</h1>
<input type="text" v-model="message" />
<h1>{{ message }}</h1>
</div>
<div style="border:1px solid red">
<h1>过滤器:处理数据</h1>
<input type="text" v-model="message" />
<h1>{{ count | addPriceIcon }}</h1>
</div>
<div style="border:1px solid red">
<h1>计算属性:数据变化才会重新执行函数,没有变化就返回之前的结果</h1>
<h1>{{ getMessage }}</h1>
</div>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'HomeView',
components: {
},
data(){
return{
count:100,
message:'hello'
}
},
// 侦听器
watch:{
message:function(newValue,oldValue){
console.log('新值' + newValue);
console.log('新值' + oldValue);
}
},
// 计算属性
computed:{
getMessage(){
return this.message.split("").reverse().join("")
}
},
// 过滤器
filters:{
//处理函数
addPriceIcon(value){
console.log(value)
return '¥' + value
}
}
}
</script>
<style scoped>
</style>
6.组件的概念,组件通信
ParentNode代码
<template>
<div>
<h1>组件的使用</h1>
<h1>{{ message }}</h1>
<Node num="1" message = "message" @alter="alterMessage"></Node>
</div>
</template>
<script>
import Node from "../components/Node.vue"
export default {
name:'ParentNode',
components:{
Node
},
data(){
return{
message:"hello"
}
},
methods:{
alterMessage(data){
this.message = data;
}
}
}
</script>
<style>
</style>
Node代码
<template>
<div>
<h1>node组件</h1>
<h1>{{ num }}</h1>
<h1>{{ message }}</h1>
<button @click="add">加1</button>
<button @click="minus">-1</button>
<button @click="alterParentNode">-1</button>
</div>
</template>
<script>
export default {
name:'Node',
props:{
num:{
type:Number,
default:0
},
message:{
type:String,
default:"h"
}
},
data(){
return{
name:'test'
}
},
methods:{
add(){
this.num++;
},
minus(){
this.num--;
},
alterParentNode(){
this.$emit('alter',this.name);
}
}
}
</script>
<style>
</style>
7.插槽,动态组件,异步组件
插槽
<template>
<div>
<h1>插槽的使用</h1>
<!-- <Node>
<div>
<h1>插槽内容</h1>
</div>
</Node> -->
<Node>
<template v-slot:header>
<div>helloworld</div>
</template>
<template v-slot:center>
<div>{{ message }}</div>
</template>
</Node>
</div>
</template>
<script>
import Node from "../components/Node.vue"
export default {
name:'ParentNode',
components:{
Node
},
data(){
return{
message:"hello"
}
},
methods:{
alterMessage(data){
this.message = data;
}
}
}
</script>
<style>
</style>
<template>
<div>
<h1>插槽</h1>
<div>
<!-- slot标签承载数据 -->
<slot name="header">默认值 </slot>
<slot name="center">默认值 </slot>
</div>
</div>
</template>
<script>
export default {
name:'Node',
data(){
return{
name:'test'
}
},
methods:{
}
}
</script>
<style>
</style>
动态组件
<template>
<div>
<h1>{{ msg }}</h1>
<button @click="update">修改</button>
</div>
</template>
<script>
export default {
name:"D",
data(){
return{
msg:'hello'
}
},
methods:{
update(){
this.msg = 'world';
}
}
}
</script>
<style>
</style>
<template>
<div class="about">
<h1>动态组件:切换组件的时候需要返回,可能我们操作了数据,需要数据不变、异步组件</h1>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
<button @click="update">切换组件</button>
</div>
</template>
<script>
// import D from '../components/D.vue'
import HomeView from './HomeView.vue'
异步组件加载
const D = () => import("../components/D.vue")
export default {
name:"AboutView",
data(){
return{
price:10,
message:"helloworld",
currentComponent:D
}
},
components:{
D,HomeView
},
methods:{
update(){
if(this.currentComponent === D){
this.currentComponent = HomeView;
}else{
this.currentComponent = D
}
}
},
watch:{
message:function(newValue,oldValue){
console.log('新值' + newValue);
console.log('旧值' + oldValue);
}
},
computed:{
getMessage(){
console.log(this.message);
return this.message.split("").reverse().join("")
}
},
//过滤器
filters:{
addPriceIcon(value){
return '¥' + value;
}
}
}
</script>
<template>
<div class="home">
<h1>HomeView</h1>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'HomeView',
components: {
},
data(){
return{
count:100,
message:'hello'
}
},
// 侦听器
watch:{
message:function(newValue,oldValue){
console.log('新值' + newValue);
console.log('新值' + oldValue);
}
},
// 计算属性
computed:{
getMessage(){
return this.message.split("").reverse().join("")
}
},
// 过滤器
filters:{
//处理函数
addPriceIcon(value){
console.log(value)
return '¥' + value
}
}
}
</script>
<style scoped>
</style>
8.生命周期,路由Vue-Router
Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue() 开始就是vue生命周期的开始。
vue生命周期可以分为八个阶段,分别是:
beforeCreate(创建前)、created(创建后)、beforeMount(载入前)、mounted(载入后)、beforeUpdate(更新前)、updated(更新后)、beforeDestroy(销毁前)、destroyed(销毁后)
1、创建前(beforeCreate)
对应的钩子函数为beforeCreate。此阶段为实例初始化之后,此时的数据观察和事件机制都未形成,不能获得DOM节点。
2、创建后(created)
对应的钩子函数为created。在这个阶段vue实例已经创建,仍然不能获取DOM元素。
一般来说,如果组件在加载的时候需要和后端有交互,放在这俩个钩子函数执行都可以,如果是需要访问props、data等数据的话,就需要使用created钩子函数
3、载入前(beforeMount)
对应的钩子函数是beforemount,在这一阶段,我们虽然依然得不到具体的DOM元素,但vue挂载的根节点已经创建,下面vue对DOM的操作将围绕这个根元素继续进行;beforeMount这个阶段是过渡性的,一般一个项目只能用到一两次。
4、载入后(mounted)
对应的钩子函数是mounted。mounted是平时我们使用最多的函数了,一般我们的异步请求都写在这里。在这个阶段,数据和DOM都已被渲染出来。
5、更新前(beforeUpdate)
对应的钩子函数是beforeUpdate。在这一阶段,vue遵循数据驱动DOM的原则;beforeUpdate函数在数据更新后虽然没立即更新数据,但是DOM中的数据会改变,这是Vue双向数据绑定的作用。
6、更新后(updated)
对应的钩子函数是updated。在这一阶段DOM会和更改过的内容同步。
##beforeUpdate和updated的钩子函数执行时机都是在数据更新的时候,beforeUpdate的执行时机是在 渲染Watcher 的before函数中,update的执行时机是在flushSchedulerQueue函数调用的时候
7、销毁前(beforeDestroy)
对应的钩子函数是beforeDestroy。在上一阶段vue已经成功的通过数据驱动DOM更新,当我们不在需要vue操纵DOM时,就需要销毁Vue,也就是清除vue实例与DOM的关联,调用destroy方法可以销毁当前组件。在销毁前,会触发beforeDestroy钩子函数。
8、销毁后(destroyed)
对应的钩子函数是destroyed。在销毁后,会触发destroyed钩子函数。
vue的生命周期的思想贯穿在组件开发的始终,通过熟悉其生命周期调用不同的钩子函数,我们可以准确地控制数据流和其对DOM的影响;vue生命周期的思想是Vnode和MVVM的生动体现和继承。
vue路由:类似于html的a标签,跳转页面的
路由的基础使用
index.js的配置文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import NextTick from '../views/NextTick.vue'
import Parent from '../views/Parent.vue'
import ParentNode from '../views/ParentNode.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/parent',
name: 'parent',
component: Parent
},
{
path: '/parentNode',
name: 'parentNode',
component: ParentNode
},
{
path: '/nextTick',
name: 'nextTick',
component: NextTick
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
9.Axios
介绍网站:https://www.oschina.net/p/axios?hmsr=aladdin1e1
vue项目安装axios:
npm install axios --save
axios获取数据
<template>
<div v-if="weather" style="text-align: center;">
<img alt="Vue logo" class="logo" src="/src/assets/logo.svg" width="125" height="125" />
<h3>{{weather.city}} 今日天气</h3>
<h3>{{weather.month[0].night.temperature}}℃ ~ {{weather.month[0].day.temperature}}℃
<img v-bind:src="img" width="20" style="vertical-align: sub;" /> {{weather.day.phrase}}
</h3>
<p>空气质量:<a>{{weather.day.air_level}}</a> 气压:<a>{{weather.day.altimeter}}mb</a> 湿度:<a>{{weather.day.humidity}}%</a></p>
<p>白天:{{weather.month[0].day.narrative}}</p>
<p>夜间:{{weather.month[0].night.narrative}}</p>
<p style="padding: 30px 0; color:#999999;">数据来源:<a href="https://tianqiapi.com/index/doc?version=worldchina" target="_blank">Tianqiapi.com</a></p>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
img: '',
weather: ''
}
},
mounted() {
let appid = '43656176';//43656176
let appsecret = 'I42og6Lm';//I42og6Lm
console.log('mounted')
axios({
method: 'get',
url: 'https://v0.yiketianqi.com/api/worldchina?appid=' + appid + '&appsecret=' + appsecret
}).then(res => {
console.log(res.data);
this.weather = res.data
this.img = 'https://xintai.xianguomall.com/skin/peach/' + res.data.day.phrase_img + '.png';
});
},
}
</script>
封装axios请求,在utils下创建一个request.js文件
import axios from 'axios'
import router from "@/router";
const request = axios.create({
baseURL: 'http://localhost:9090',
timeout: 5000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user = localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : null
if (user) {
config.headers['token'] = user.token; // 设置请求头
}
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
// 当权限验证不通过的时候给出提示
if (res.code === '401') {
// ElementUI.Message({
// message: res.msg,
// type: 'error'
// });
router.push("/login")
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
10.Vuex
概念:状态管理模式,集中管理共享状态
vuex的js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: { //存储数据
count:100,
name:'helllo'
},
getters: {
},
mutations: { //操作方法
setCount(state){
state.count++;
},
minusCount(state,num){
state.count -= num;
}
},
actions: {
asyncIncrement(context,num){ //异步操作
setTimeout(() => {
context.commit('setCount',num)
},1000)
}
},
modules: {
}
})
基本使用
<template>
<div class="about">
<h1>This is an about page</h1>
<h1>VueX的数据:{{ $store.state.count}}</h1>
<h1>VueX的数据:{{ count}}</h1>
<h1>VueX的数据:{{ name}}</h1>
<button @click="changeCount">增加</button>
<button @click="minusCount1">减少10</button>
</div>
</template>
<script>
import {mapState,mapMutations,mapActions} from 'vuex'
export default {
data() {
return {
img: '',
weather: ''
}
},
computed:{
...mapState(['count','name']) //读取vuex的数据c'c
},
methods:{
...mapMutations(["minusCount","setCount"]),
...mapActions(["asyncIncrement"]),
minusCount1(){
// this.$store.commit('minusCount',10);
this.minusCount(10)
},
changeCount(){
// this.$store.commit('setCount')
this.setCount();
//this.$store.dispatch("asyncIncrement");//异步
}
}
}
</script>