Vue基础——生命周期&基础指令&组件技术

Vue

一. 创建vue项目

tianqideMBP:try-vue tianqizhao$ vue init webpack hello

? Project name hello
? Project description A Vue.js project
? Author tianqi-zhao <tianqizhao.judy@gmail.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset (Use arrow keys)
❯ Standard (https://github.com/standard/standard) 
  Airbnb (https://github.com/airbnb/javascript) 
  none (configure it yourself) 
? Set up unit tests Yes
? Pick a test runner (Use arrow keys)
❯ Jest 
  Karma and Mocha 
  none (configure it yourself) 
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recom
mended) (Use arrow keys)
❯ Yes, use NPM 
  Yes, use Yarn 
  No, I will handle that myself 
  
  vue-cli · Generated "hello".

# Installing project dependencies ...
# ========================

二. 先来个例子感受一下

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	</head>
	<body>
		<div id = "app">
			<h1>{{mymessage}}</h1>
			<input v-model="mymessage" />
		</div>
	</body>
	<!-- MV VM 双向绑定-->
	<script>
		var vue = new Vue(
			{
				el:'#app',
				data:{
					mymessage:"hello world"
				}
			}
		)
	</script>
</html>

这种方式使用的vue与html中的js的变量对象相似,是html先加载到界面上,之后使用vue对象对其进行更改。

vue对象的属性el是用来指定其能更改的部分,所以需要将div绑定id,并查找这个id带指的标签,交给vue进行控制。

vue构造函数通过传入一个json对象初始化其内部内容。

三. vue生命周期

clipboard.png

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>vue生命周期学习</title>
  <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
  <div id="app">
    <h1>{{message}}</h1>
		<input v-model="message" />
  </div>
</body>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue的生命周期'
    },
    beforeCreate: function() {
      console.group('------调用钩子函数beforeCreate------');
      console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
      console.log("%c%s", "color:red","message: " + this.message) 
    },
    created: function() {
      console.group('------调用钩子函数created------');
      console.log("%c%s", "color:red","el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化
    },
    beforeMount: function() {
      console.group('------调用钩子函数beforeMount------');
      console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
      console.log(this.$el);
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
    },
    mounted: function() {
      console.group('------调用钩子函数mounted------');
      console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
    },
    beforeUpdate: function () {
      console.group('调用钩子函数beforeUpdate===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);   
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    updated: function () {
      console.group('调用钩子函数updated===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el); 
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    beforeDestroy: function () {
      console.group('调用钩子函数beforeDestroy===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    destroyed: function () {
      console.group('调用钩子函数destroyed===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);  
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message)
    }
  })
</script>
</html>

在这里插入图片描述

------调用钩子函数beforeCreate------ 
el     : undefined 
data   : undefined 
message: undefined

在这里插入图片描述

init injections & reactivity 这步初始化data和message

------调用钩子函数created------ 
el     : undefined 
data   : [object Object]
message: Vue的生命周期

在这里插入图片描述

在调用钩子函数beforeMount之前,检测el标签所指代的内容,并将outerHTML编译为模板,将模板编译为render函数

------调用钩子函数beforeMount------ 
el     : [object HTMLDivElement] 
	<div id="app">
data   : [object Object] 
message: Vue的生命周期

在这里插入图片描述

根据之前的outerHTML/template/render()渲染得到的dom树,创建vm.$el并赋值给el元素所指代部分

------调用钩子函数mounted------ 
el     : [object HTMLDivElement] 
	<div id="app">
data   : [object Object]
message: Vue的生命周期

此时结束后,页面已经处于Mounted状态了,接下来就等待有更改发生,才会触动其他钩子事件:

更改input内容为“Vue的生命周“,上方h1标签和input内容message绑定,此时触发状态转变,调用钩子函数beforeUpdate()

在这里插入图片描述

调用钩子函数beforeUpdate===============》
el     : [object HTMLDivElement] 
	<div id="app">
		innerHTML: "<h1>Vue的生命周期</h1> <input>"
		innerText: "Vue的生命周期"
data   : [object Object]

在这里插入图片描述

Virtual DOM re-render and patch:根据vue对象内部更改的信息,更改虚拟DOM树,对DOM树“打补丁”进行修改

调用钩子函数updated===============》 
el     : [object HTMLDivElement] 
	<div id="app">
		innerHTML: "<h1>Vue的生命周</h1> <input>"
		innerText: "Vue的生命周"
data   : [object Object]
message: Vue的生命周

在这里插入图片描述

四. 指令

4.1 View视图模板部分:
4.1.1 数据绑定:
4.1.1.1 v-bind

title标签是鼠标悬停到上方时,有标签“提示”弹出来。

vue框架将title属性的内容绑定给Vue:data里面的变量

例子一:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
	</head>
	<body>
		<div id="app">
			<div v-bind:title="mymessage">
				try2
			</div>
			<div :title="mymessage">
				try
			</div>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				mymessage:"hello world",
			}
		})
	</script>
</html>

在这里插入图片描述

例子二:

v-bind可以绑定class,修改标签style类型

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<style>
		.container{
			width: 100px;
			height: 100px;
		}
		.state1{
			background-color: red;
		}
		.state2{
			background-color: yellow;
		}
		.state3{
			background-color: #008000;
		}
	</style>
	<body>
		<div id="app">
			<button @click="change">红绿灯</button>
			<div :class="{container:true,state1:state==0,state2:state==1,state3:state==2}">
			</div>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				state:0
			},
			methods:{
				change(){
					this.state = (this.state+1)%3
				}
			}
		})
	</script>
</html>
4.1.1.2 v-model

v-bind和v-model的区别在于:

v-bind为单向绑定,是MV模式,只是将model里面的内容显示在view视图上。其简写为:value='model数据'

v-model是双向绑定,是MV VM模式,多出来的VM是指view视图的变化会影响model。

例子一:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<input v-model="text" />
			<input :value="text" />
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				text:"v-model"
			}
		})
	</script>
</html>

效果:

在这里插入图片描述

例子二:

form表单使用v-model

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<form>
				java<input type="checkbox" name="likes" value="java" v-model="likes"/>
				css<input type="checkbox" name="likes" value="css" v-model="likes"/>
				c++<input type="checkbox" name="likes" value="c++" v-model="likes"/>
				<div></div><input type="radio" name="gender" v-model="gender" value="male"/><input type="radio" name="gender" v-model="gender" value="female"/>
				
				<select v-model="countryid">
					<option v-for="item in conutries" :value="item.key">
						{{item.name}}
					</option>
				</select>
			</form>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				likes:["java","css","c++"],
				gender:"female",
				conutries:[
					{key:1,name:"America"},
					{key:2,name:"China"},
					{key:3,name:"Japan"},
				],
				countryid:2
			}
		})
	</script>
</html>

Checkbox中v-model的值为选定的多个值

radio中v-model的值为选定的单个值

select中v-model设置option中的value进行选择

4.1.2 v-if

效果是页面初始状态为“登陆”字符,点击之后,变为“登出”。反复点击反复跳转

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
	</head>
	<body>
		<div id="app">
			<button v-on:click="login">
				<span v-if="!islogin">
					登陆
				</span>
				<span v-if="islogin">
					登出
				</span>
			</button>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				islogin:false
			},
			methods:{
				login(){
					this.islogin = !this.islogin;
				}
			}
		})
	</script>
</html>
4.1.3 v-for

v-for="(people,i) in list",people为list里面的item,i为索引

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<ul>
				<li v-for="(people,i) in list">
					{{i}}--{{people.name}},{{people.age}}
				</li>
			</ul>
			<table>
				<tbody>
					<tr v-for="(people,i) in list">
						<td>{{i}}</td>
						<td>{{people.name}}</td>
						<td>{{people.age}}</td>
					</tr>
				</tbody>
			</table>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				list:[
					{
						name:"哥哥",
						age:22
					},
					{
						name:"姐姐",
						age:18
					},
					{
						name:"小朋友",
						age:8
					}
				]
			}
		})
	</script>
</html>
4.1.4 v-on

v-on简写可以写为@

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<h1>{{message}}</h1>
			<button @click="reverse">反过来</button>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				message:"你真棒"
			},
			methods:{
				reverse(){
					this.message = this.message.split('').reverse().join('')
				}
			}
		})
	</script>
</html>

效果是点击按钮反转“你真棒”为“棒真你”

4.2 Model模型部分指令:
4.2.1 computed
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<input v-model="price" />
			<h>{{readblePrice}}</h><!-- 需要计算的参数 -->
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				price:0
			},
			computed:{
				readblePrice:function(){
					return this.dealNumberToMoney(this.price)
				}
			},
			methods:{
				//将数字每三个用逗号隔开输出
				dealNumberToMoney(money){
					var fmtAmt = "";
					if(money&&money!=null){
					    money = money.replace(/,/g,"").replace(/,/g,"");
					    if(money.indexOf(".")==-1){
					        money = money + ".00";
					    }
					    
					    var index = money.indexOf(".");
					    var floatValue = money.substring(index+1);
					    
					    var count = 0;
					    for(var i=(index);i>=0;i--){
					        fmtAmt = money[i]+fmtAmt;
					        if(count==3&&i!=0){
					            fmtAmt = "," + fmtAmt;
					            count = 0;
					        }
					        count++;
					    }
					}
					fmtAmt += floatValue;
					return fmtAmt;   
				}
			}
		})
	</script>
</html>

在这里插入图片描述

4.2.2 watched监听

当一个数据模型data发生变化时,进行某一种操作

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<input v-model="husband" />
			<input v-model="wife" />
			<input :value="price" readonly="true"/>
			<div>
				{{state}}
			</div>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el:'#app',
			data:{
				husband:"约翰",
				wife:"",
				state:"",
				price:1000
			},
			watch:{
				wife:function(){
					if(this.wife == ""){
						this.state = "单身狗"
					}else{
						this.state = "小情侣"
					}
				},
				husband:function(){
					this.price = this.price+100
				}
			}
		})
	</script>
</html>

效果:husband和wife两个input栏具有事件监听事件。husband变化,price栏数字加100。wife变化,若为空,则下部分div为“单身狗”,否则为“小情侣”。

在这里插入图片描述

五. 组件技术

首先需要先使用vue脚手架新建一个vue项目。(要求已经按照vue脚手架)

一个最初始的vue项目src主要有:assest(图片),components(vue文件),router(js路由文件),外层组件App.vue, main.js

程序初始运行时,首先进入main.js文件。

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

在js文件里面,创建了Vue对象,将其构造所需要的参数传入其中。每一个import的都是一个组件。

注意el标签提供的是template模板的挂载点。

在template模板App中定义了id为“app”的挂载点。

<template>
  <div id="app">
    <img src="./assets/login.png">
    <router-view/>
  </div>
</template>

组件App使用了,这个标签会根据url路径进行路由:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

这个路由的意思是,当path为“/”时,将使用组件‘HelloWorld’替换。

通常情况下,我们的路径信息会跳转为:

在这里插入图片描述

而“#”表示单页应用,在其页面内进行路由。

整个过程,最为重要的就是将vue文件视作一个vue对象组件。而组件又可以在其他的vue组件中进行引用。

我将组件的引用加载技术分为两类:

5.1 通过路由加载组件

第一种方法是通过替换达到使用组件的目的。

如此加载组件的必要条件是:在router中将路径与组件进行匹配

目前我的router中的index.js文件中routes配置如下:

routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/hello',
      name: 'myHello',
      component: MyHello
    }
  ]

因此,在不同的输入地址下,它会显示出不同的内容(被不同组件替换)

在这里插入图片描述
在这里插入图片描述

5.2 直接对组件进行引用

很多时候,我们用不着跳转,只是想将组件分开写,使代码更有结构性,让组件可复用。

那么这个时候,就直接将外部组件在模型中import并声明,就可以渲染到template标签中了。

看个例子

<template>
    <div>
        <sun-sun></sun-sun><!-- 驼峰在这里面改成“-”,规范 -->
    </div>
</template>

<script>
import sun from "../view/myComponents.vue"

export default {
    name: "myHello",
    data(){
    },
    components:{
      sunSun:sun
    }
}
</script>

<style>
</style>

注意:采用驼峰命名法是因为在webpack中所有名称都会被转变为小写

可以看到template,div中引用了名称为:sunSun的组件。在vue实例创建的过程中,会通过动态渲染,将该部分替换称为"…/view/myComponents.vue"这个组件。

<template>
  <div>
    <form><select id="province" v-model="pid">
        <option v-for="(proItem,id) in provinces" :value="id">
          {{proItem}}
        </option>
      </select><select id="city" v-model="cid">
        <option v-for="(cityItem,id) in cities" :value="id">
          {{cityItem}}
        </option>
      </select><select id="district" v-model="did">
        <option v-for="(districtItem,id) in district" :value="id">
          {{districtItem}}
        </option>
      </select>
    </form>
  </div>
</template>

<script>
  import area from "../data/area.js"
  export default{
    name:"son",
    data(){
      return {
        pid:"",
        cid:"",
        did:"",
        provinces: area["0"],
        cities: null,
        district: null
      }
    },
    watch:{
      pid:function(){
        var indexStrC = "0,"+this.pid
        this.cities = area[indexStrC]
        this.district = null
      },
      cid:function(){
        var indexStrD = "0,"+this.pid+","+this.cid
        this.district = area[indexStrD]
      }
    }
  }
</script>

<style>
  select{
    width: 100px;
  }
</style>

这个组件是一个省市区三级联动的下拉框

在这里插入图片描述

其数据存在"…/data/area.js"中

5.4 组件间的通信

组件间有两种通信方式,第一种是父组件向子组件传值,第二种是子组件向父组件传值。

外加一个比较特殊的插槽用法。

5.4.1 父组件向子组件传值

父组件向子组件传值很简单,父组件只需要在子组件处声明要传递的值,并为其赋值。(子组件名称为prop)

<prop mymsg="hello world"></prop>

子组件需要在模型部分使用props接受这个值,即可与data()内返回的数据具有相同的用法。

<template>
  <div>
    {{msg}}
  </div>
</template>

<script>
  export default{
    name: "prop",
    props:["mymsg"]//获取父组件传过来的值
  }
</script>
5.4.2 子组件向父组件传值

子组件向父组件传值需要触发父组件的事件。

首先在子组件部分需要使用this.$emit触发自定义的事件,这个函数需要传入事件的名称,以及要传输的数据

<template>
  <div>
    <input v-model="messageToFather" />
    <button @click="sendMessgae">send</button>
  </div>
</template>

<script>
  export default{
    name:"sendmessage",
    data(){
      return{
        messageToFather:""
      }
    },
    methods:{
      sendMessgae(){
        this.$emit("event",{sendMessgae:this.messageToFather})//核心函数
      }
    }
  }
</script>

而父组件处需要将子组件与这个事件绑定,并进行相应:

<template>
    <div>
        <div>
        <send-message @event="showMessage"></send-message><!-- 父组件绑定这个事件,并通过showMessage()进行响应 -->
        <div v-model="sonMessage">
          这里是子组件传过来的值:{{sonMessage}}
        </div>
    </div>
</template>

<script>
import sendMessgae from "../view/sendMessage.vue"

export default {
    name: "myHello",
    data(){
        return {
            sonMessage:""
        }
    },
    methods:{
        showMessage(data){
          console.log(arguments)
          this.sonMessage = data["sendMessgae"]
        }
    },
    components:{
      sendMessage:sendMessgae,
    }
}
</script>

最后显示结果为:在这里插入图片描述

点击send按钮,会想input的输入内容显示在下方。

5.4.3 插槽

插槽就是将子组件当作一个槽,插进去的是父组件提供的数据

子组件:

<template>
  <div>
    这里是子组件,下️面是父组件
    <div>
      <slot></slot><!-- 这里就是槽 -->
    </div>
    子组件
  </div>
</template>

父组件

父组件将myslot.vue作为组件导入为mySlot,并在模板中使用。最后渲染的时候,将父组件的部分替换掉子组件的部分。并将子组件的所有替换掉父组件的部分

<template>
    <div>
        <my-slot>
          我是父组件
        </my-slot>
    </div>
</template>

<script>
import mySlot from "../view/mySlot.vue"

export default {
    name: "myHello",
    components:{
      mySlot:mySlot
    }
}
</script>

效果:在这里插入图片描述

其中作用域插槽需要特别注意,作用域插槽是数据由子组件提供,但是父组件可以使用子组件的数据

更多关于插槽:https://juejin.im/post/5a69ece0f265da3e5a5777ed

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值