Vue入门

第01天_Vue入门

学习路线图: HBuilderX工具的使得->了解Vue工作原理-> 模板语法->组件化->vue-cli完整项目开发

1. Vue介绍

​ Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

学习Vue需要有一定的预备知识, 需要了解HTML、CSS 和 JavaScript 的中级知识。如果你刚开始学习前端开发,将框架作为你的第一步可能不是最好的主意——掌握好基础知识再来吧!之前有其它框架的使用经验会有帮助,但这不是必需的。

2. MVC&MVVM

2.1 MVC

​ MVC 模式(Model–View–Controller)是软件工程中的一种软件架构模式,它把软件系统分为三个基本部分:模型(Model)视图(View)控制器(Controller)

2.2 MVVM框架

​ MVVM是由MVC进一步发展而来, 还是分为三个部分: 模型(Model)视图(View)控制器(VM)

​ 数据驱动(即是双向的数据绑定) DOM是数据的一种自然映射。双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的。Vue对象的改变会直接影响到HTML的标签的变化,而且标签的变化也会反过来影响Vue对象的属性的变化。之前DOM驱动的开发方式尤其是以jQuery为主的开发时代,都是DOM变化后,触发js事件,然后在事件中通过js代码取得标签的变化,再跟后台进行交互,然后根据后台返回的结果再更新HTML标签,异常的繁琐。有了Vue这种双向绑定, 让开发人员只需要关心json数据的变化即可,Vue自动映射到HTML上,而且HTML的变化也会映射回js对象上,开发方式直接变革成了前端由数据驱动的开发时代。

https://baike.baidu.com/pic/MVVM/96310/0/e61190ef76c6a7efe4baffc3fdfaaf51f2de66b2?fr=lemma&ct=single

###3. 模板指令

开发工具的选择: 开发vue的工具有很多,比较主流的有vscode、hbuild、webstorm,官方推荐使用hbuildx。可以到官方网站上下载hbuildX软件。

3.1 Vue入门

​ Vue 可以直接把它当做一个js库使用,可以很简单的接入到你的项目中,或者你只需要使用双向数据绑定。

需求: 网页中有个div标签, 而需要有json对象存储数据,把json对象上的数据放到div。

3.1.1 引入Vue库
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
3.1.2 在div标签声明app
<div id='app'>app>
3.1.3 创建Vue对象

创建Vue的对象并把数据绑定到上 创建好的div上去, 以下是完整的代码

<head>
		<meta charset="utf-8">
		<title>title>
		
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
		<div id="app">
			<p>message: {{ message }}p>
		div>
body>
<script>
		new Vue({
			// el: element, 让vue绑定一个元素节点(使用css选择器进行匹配)
			el: '#app',
			
           // data: 数据选项,用来存放数据
			data: {
				message: "教育"
			},
		})
script>
3.2 模板指令

通过模版指令(写在html中的),即是html和vue对象的粘合剂。

3.2.1 数据渲染

数据渲染有v-textv-html{{ }} mustache三种方式,用法如下:

<body>
  <div id="app">
			
			<div>
				<p>{{ name + 1 }}p>  
				<p v-text="name">p>  
				<p v-html="name">p>  
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
				name: "教育"
			}
		})
script>

v-text更新元素的textContent, v-html更新元素的innerHTML ,内容按普通HTML插入,不会作为 Vue 模板进行编译。

3.2.2 控制标签

主要用于显示隐藏,包括v-ifv-showv-elsev-else-if,用法如下:

<body>
  <div id="app">
			
			<div>
				<p v-if="isShow">科比p>   
				<p v-else="isShow">詹姆斯p>
				
				<p v-show="isShow">库里p>  
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
				isShow: false
			}
		})
script>

v-if是直接不渲染该元素; v-show是通过display: none进行隐藏;

3.2.3 渲染循环

模板引擎都会提供循环的支持,渲染循环使用v-for。 基本的用法类似于foreach的用法,详细参考以下代码:

<body>
  <div id="app">
			
			<div>
				<ul>
					<li v-for="item in stars">
						{{ item.name }}
					li>
				ul>
				<ul>
					<li v-for="(item, index) in stars">
						{{index}}: {{ item.name }}
					li>
				ul>
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
				stars: [
					{name: "鹿晗"},
					{name: "蔡徐坤"},
					{name: "李易峰"},
					{name: "吴亦凡"},
				],
			}
		})
script>
3.2.4 事件绑定

事件绑定使用v-on:事件名或者快捷方式@事件名,详细用法如下:

<body>
  <div id="app">
    
    	<p v-show="isShow">科比p>

			
			<div>
				<button v-on:click="btnClick">按钮button>
				<button @click="btnClick">按钮button>  
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
				isShow: false
			},
      methods:{
				btnClick() {
					this.isShow = !this.isShow
				}
			}
		})
script>

示例2:

  • {{ index }}- {{ item.name }}

    {{ item.id }}

3.2.5 属性绑定

Vue中不能直接使 {{ expression}} 语法进行绑定html的标签,而是用它特有的v-bind指令。

语法: <标签 v-bind:属性名="要绑定的Vue对象的data里的属性名">

由于v-bind使用非常频繁,所以Vue提供了简单的写法,可以去掉v-bind直接使用:即可。

<body>
  <div id="app">
			
			<div>
				<img v-bind:src="imgsrc" width="100" />
				<img :src="imgsrc" width="100" />  
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
				imgsrc: 'https://cn.vuejs.org/images/logo.png'
			}
		})
script>

示例2:

DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Vue二之数据绑定title>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
		<style>
			.small{
				width: 100px;
				height: 60px;
			}
			
			.big{
				width: 400px;
				height: 300px;
			}
		style>
	head>
	<body>
		<div id="app">
			
			<button @click="cover_cls='big'">放大图片button>
			<button @click="cover_cls='small'">缩小图片button>
			<button @click="width -= 10">减宽button>
			<button @click="width += 10">加宽button>
			<button @click="height -= 10">差高button>
			<button @click="height += 10">加高button>
			<br>
			<img
			 :width="width" :height="height"
			 :src="cover" @click="swithCover">
			
		div>
		<script>
			let covers = [
				'http://photo.tuchong.com/3199480/f/22860762.jpg',
				'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fphoto.tuchong.com%2F19348387%2Ff%2F811803390.jpg&refer=http%3A%2F%2Fphoto.tuchong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639019842&t=c08a6daebe3f6ba7ed23dad4eb87fe47',
				'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fww2.sinaimg.cn%2Fmw690%2F9e3738f9gy1gw6vmdezsxj20u00mi45r.jpg&refer=http%3A%2F%2Fwww.sina.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639019842&t=e28ab3482c54f1d7a58e721dfb83b94f',
				'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fww1.sinaimg.cn%2Fmw690%2F9e3738f9gy1gw6vmds4q4j20u00mjwnb.jpg&refer=http%3A%2F%2Fwww.sina.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639019842&t=ac697b1c5089740f9cca5531458d5233'
			]
			new Vue({
				el: '#app',
				data: {
				   cover: 'http://photo.tuchong.com/3199480/f/22860762.jpg',
				   cover_cls: 'big',
				   width: 200,
				   height: 300
				},
				methods: {
					swithCover(){
						index = Math.floor(Math.random()*4)
						console.info('--->cover index: '+index)
						// this是当前Vue的实例对象
						this.cover = covers[index]
					}
				}
			})
		script>
	body>
html>
3.2.6 双向数据绑定

针对的是输入框input和form表单

双向数据绑定使用v-model,实现两个组件的数据同步,如本文框与计算结果同步。

<body>
  <div id="app">
			
			<div>
				<input type="text" v-model="val">
				val值: {{val}}
			div>
  div>
body>
<script>
		new Vue({
			el: '#app',
			data: {
					val:"千锋教育"
			}
		})
script>

4. Vue实例属性

​ Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理、数据模型等,当然它也有自己的一系列的生命周期的事件钩子 ,辅助我们进行对整个Vue实例生成、编译、 挂载、销毁等过程进 js控制。

4.1 重要选项
  • data数据选项

    代表vue对象的数据 创建的Vue对象中的data属性就是用来绑定数据到HTML的, Vue框架会自动监视data里面的数据变化,自动更新数据到HTML标签上去。

  • methods方法选项

    methods方法选项代表vue对象的方法, 方法中的 this 自动绑定为 Vue 实例。

  • computed计算属性

在做数据的绑定的时候,数据要进行处理之后才能展示到html页面上,虽然vue提供了非常好的表达式绑定的方法,但是只能应对低强度的需求,另外放入太多的逻辑会让模板过重且难以维护。 而计算属性,即属性可以是一个方法

  • watch监听选项

设置了对象的监听方法, 一个对象,键是需要观察的表达式,值是对应回调函数。 值也可以是方法名,或者包含选项的对象。

4.2 案例: 商品结算

​ 我们通过一个案例来了解以上介绍的几个重要选项的运用

<head>
		<meta charset="utf-8">
		<title>title>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>
		<div id="app">
			iphone11Pro Max
			<p>价格: {{ price }}p>
			<p>数量:
				<button @click="sub">-button>
				{{ num }}
				<button @click="add">+button>
			p>
			<p>总价: {{ total }}p>
		div>
body>
<script>
		new Vue({
			el: "#app",
			// 数据选项
			data: {
				price: 10000,
				num: 1,
			},
			// 方法选项
			methods: {
				sub() {
					this.num--
				},
				add() {
					this.num++
				}
			},
			// 计算属性选项
			computed: {
				total() {
					return this.price * this.num;
				}
			},
			// watch: 监听属性选项
			watch: {
				num(newVal, oldVal) {
					if (newVal < 1 || newVal > 10) {
						this.num = oldVal;
					}
				}
			}
			
		})
script>

5. 组件化

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。

5.1. 组件介绍

Vue组件 *.vue 由三部分组成分别是:

  • HTML代码
  • javascript脚本
  • css样式。

【官方推荐】将三个部分都写到一个 .vue 件中。

5.2 创建组件
5.2.1 全局组件

全局组件可以应用于多个Vue实例中,使用 Vue.component(tagName, options),如下:

Vue.component('my-component', {
  template: '
A custom component!
'
})

【注意】自定义标签名,但尽量遵循W3C规则(小写,并且包含一个短杠),vue中不强制遵循这一规则。

5.2.2 局部组件

局部组件一般仅在某一个Vue实例中使用,从作用域来说是局部的,如:

var Child = {
  template: '
A custom component!
'
} new Vue({ // ... components: { // 将只在父模板可用 'my-component': Child } })
5.3 使用组件

使用组件非常简单,在vue实例渲染的页面标签中,将组件名作为标签名使用即可:

<div id="main">
  <my-component>simple-counter>
  <my-component>simple-counter>
div>

综合示例:

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">
			<div>
				<el-button msg='Ok'>el-button>
				<el-button msg='Cancel'>el-button>
				<el-label title='价格'>el-label>
				
			div>
			
		div>
		<div id="app2">
			<el-button msg='yes'>el-button>
			<el-button msg='no'>el-button>
			<el-label title='名称'>el-label>
		div>
		<script>
			// 全局的组件
			Vue.component('el-button', {
				template: '',
				props: {
					msg: String
				},
				data(){
					return {}
				}
			})
			
			let vm1= new Vue({
				el: '#app',
				components:{
					'el-label': {
						template: '',
						props: {
							title: String
						}
					}
				}
			})
			
			let vm2 = new Vue({
				el: '#app2'
			})
		script>
	body>
html>
5.4 组件的数据

组件模板中使用的变量数据,可以在组件data(这是一个函数)中声明,如:

var data = { counter: 0 } // 全局变量,组件被多次使用时,共用一个data
Vue.component('simple-counter', {
  template: '',
  data: function () {
    return data
  }
})

new Vue({
  el: '#example-2'
})

以上代码中,data声明是全局变量,通过以下页面渲染后,点击某一个按钮会影响其它按钮的结果。

<div id="example-2">
  <simple-counter>simple-counter>
  <simple-counter>simple-counter>
  <simple-counter>simple-counter>
div>

因为data是全局的变量,会影响其它相同的组件显示的值,因此可以局部变量,如下:

Vue.component('simple-counter', {
  template: '',
  data: function () {
    return { counter: 0 }  // 每渲染一次组件,则返回新的data对象
  }
})

new Vue({
  el: '#example-2'
})
5.5 组件通信

组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。

在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。如下图所示:

5.5.1 父层传值

父层向子层传值使用props属性,如下:

Vue.component('child', {
  props: ['message'],
  template: '{{ message }}'
})

在父层模板中,使用如下:

<child message="hello!">child>

当然如果使用父层vue实例的data中变量(动态绑定)也可以, 如下所示:

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg">child>
div>

【注意】在props声明属性时,可以指定属性类型(Number、String、Boolean、Array、Object、Function)和required属性(boolean类型,表示是否必要属性),如下所示:

Vue.component('example', { 
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})
5.5.2 子层传值

子层(组件)将内部发生变量的数据向父层传递时,一般使用v-on事件。

当然每个Vue实例都实现了事件接口(Events interface):

  • 使用$on(eventName) 监听事件
  • 使用$emit(eventName) 触发事件

案例如下:

<div id="counter-event-example">
  <p>{{ total }}p>
  <button-counter v-on:increment="incrementTotal">button-counter>
  <button-counter v-on:increment="incrementTotal">button-counter>
div>

父层模块中监听increment事件,监听的方法是incrementTotal

// 子层
Vue.component('button-counter', {
  template: '',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    increment: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})

// 父层
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})

在子层组件中绑定数据和事件,并在事件方法中通过组件对象的$emit触发外部组件(父级)事件。

综合练习:

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">
			<p>总数: {{ total }}p>
			<el-counter @add='addHandler' @sub='subHandler'>el-counter>
			<el-counter @add='addHandler' @sub='subHandler'>el-counter>
			<el-counter @add='addHandler' @sub='subHandler'>el-counter>
			<el-counter @add='addHandler' @sub='subHandler'>el-counter>
			<el-counter @add='addHandler' @sub='subHandler'>el-counter>
		div>
		<script>
			let data = {n: 0} // 全局的数据
			Vue.component('el-counter', {
				template: '
{{ n }}
'
, data(){ return {n: 0} // 局部的数据 }, watch:{ n(n_, o_){ if(n_ < 0){ this.n = o_ } } }, methods:{ add(){ this.n++ this.$emit('add') }, sub(){ this.n-- if(this.n >= 0) this.$emit('sub') } } }) new Vue({ el: '#app', data: { total: 0 }, methods:{ addHandler(){ //接收子组件的加1的信号 this.total++ }, subHandler(){ //接收子组件的减1的信号 this.total-- } } })
script> body> html>

购物车实战:

DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>购物车效果title>
		<script src="https://unpkg.com/axios/dist/axios.min.js">script>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
		<style>
			.row{
				display: flex;
				flex-direction: row;
				justify-content: space-between;
				align-items: center;
				flex-wrap: nowrap;
			}
			
			.row .cover{
				height: 100px;
				width: 80px;
				border-radius: 10px;
				box-shadow: 5px 5px 5px lightcyan;
				margin: 5px;
			}
			.bold {
				font-weight: bold;
				color: blue;
			}
			.content {
				width: 100%;
			}
			.content>div{
				margin: 5px;
			}
			
			.btn{
				width: 100%;
				height: 45px;
				background-color: red;
				color: white;
				padding: 10px;
			}
			.btn:active{
				opacity: 0.8;
			}
			.btn:hover{
				cursor: pointer;
				background-color: darkred;
			}
			
			ul,li{
				margin: 0;
				padding: 0;
				list-style: none;
			}
			.col{
				display: flex;
				flex-direction: column;
				flex-wrap: nowrap;
			}
			
			.total{
				display: inline-block;
				background-color: red;
				color: white;
				width: 15px;
				height: 15px;
				border-radius: 50%;
				font-size: 0.5rem;
				text-align: center;
				opacity: 0.8;
			}
			
			.top-total{
				text-align: right;
				position: relative;
				right: 10px;
				top: 10px;
			}
			.cart {
				background-color: lightgray;
				padding-bottom: 5px;
				border: 1px solid lightblue;
				height: 40px;
			}
			
			.cart-div{
				width: 800px;
				height: 600px;
				position: absolute;
				background-color: lightcyan;
				left: 50%;
				top: 50%;
				transform: translate(-50%, -50%);
			}
		style>
	head>
	<body>
		<div id="app">
			<div style="width: 100px; height: 35px;" class="cart" @click="isshow=true">
				<div class="top-total"><span class="total">{{cart_total}}span>div>
				<div >我的购物车div>
			div>
			<ul>
				<li v-for="g in goods">
					<div class="row">
						<img class="cover" :src="'http://182.61.29.85'+ g.goodsimg">
						<div class="content">
							<div class="bold">{{ g.goodsname }}div>
							<div>
								原价: <span style="text-decoration: line-through;color:lightgray"> ¥{{ Math.round(parseFloat(g.price) * 1.5) + '.00'}}span>
								<span style="color: red;">会员价:  ¥{{ g.price }}span>
							div>
							<div>
								<span>限购件数: {{ g.sales_volume }}span>
							div>
						div>
						<div style="text-align: right; width: 200px">
							<span @click="addCart(g)" class="btn">加入购物车span>
						div>
					div>
				li>
			ul>
			<div class="cart-div" v-show="isshow">
				<h3>我的购物车h3>
				<button @click="isshow=false">关闭button>
				<ul>
					<li v-for="g in carts">
						{{ g.name }}-{{g.price}} <button>-button> <input v-model="g.cnt" size="1"><button>+button>
					li>
				ul>
				<div>
					总价格: ¥ {{ total_price }}
				div>
			div>
		div>
		<script>
			// Vue生命周期的方法: create,mounte,update, destroy
			axios.defaults.baseURL = 'http://182.61.29.85'
			
			new Vue({
				el: '#app',
				data: {
					goods: [],
					cart_total: 0,
					carts: [],
					isshow: false
				},
				created() {
					axios.get('/api/new/').then(response=>{
						console.info(response)
						if(response.status === 200){
							// alert('已加载数据')
							// response.data => {msg:'', data: []}
							this.goods = response.data
							console.info(this.goods)
						}
					}).catch(error=>{
						console.error(error)
					})
				},
				methods: {
					addCart(item){
						
						this.carts.push({name: item.goodsname, price: item.price, cnt: 1})
						this.cart_total ++
					}
				},
				computed:{
					total_price(){
						let tp = 0
						this.carts.forEach(item=>{
							tp += item.price*item.cnt
						})
						
						return tp
					}
				}
			})
		script>
	body>
html>

6. 扩展

6.1 vscode+vue插件
6.1.1 下载vscode

官网下载地址: https://code.visualstudio.com/

6.1.2 安装vue相关插件

vscode安装的插件较多,详细如下:

  • vetur 写vue必备插件
  • Path Intellisense 路径自动补全
  • Auto Close Tag 自动闭合标签
  • Auto Rename Tag 当改标签名字是,同时修改闭合标签
  • Beautify 和 vue-beautify 格式化文件, 保证正确的缩进
  • HTML CSS Support CSS提示插件
  • JavaScript (ES6) code snippets es6代码提示插件
  • VSCode Great Icons 给文件夹增加图标的插件
6.2 chrome安装vue插件
6.2.1 基于chrome助手

下载一个chrome的助手(链接:https://pan.baidu.com/s/1u8vqWJUSedASDPFC9op70Q 密码:7w4c)

下载完成后,自行解压,然后打开chrome的插件管理器(chrome://extensions/), 点击"加载已解压的扩展程序",在弹出的文件目录选择对话框中,选择chrome助手的目录即可。

6.2.2 基于git+npm

在github上下载压缩包并解压到本地,github下载地址:https://github.com/vuejs/vue-devtools

下载完成后打开命令行cmd进入vue-devtools-master文件夹,执行如下命令:

npm install
npm run build

编译完成之后,将生成的shells下的chrome文件夹安装到chrome扩展程序中即可。

6.3 HBuilderX的技巧
6.3.1快速生成标签
标签名>二级标签名*n>三级标签名*n  + tab键 
6.3.2 快速生成外部标签
选择某一标签区域 + 快捷键 ctrl+]
6.3.3 缩进
ctrl+Shift 取消(向左缩进)
tab 向右缩进
6.3.4 反包围
Ctrl+Shift+] 可去掉父级标签并自动处理子节点的缩进
6.3.5 批量合并或换行
Ctrl+Shift+k,可以把每个css的区块代码都合并为一行
ctrl+k,  自动格式化换行
6.3.6 注释
ctrl + / 行注释
ctrl+alt + / 块注释

你可能感兴趣的:(前端,vue,前端框架)