CSDN - 盛洪宇(技术胖) - Vue2.x从入门到实战

Vue 全家桶 - Webpack / Vue / Vue-cli / Vue-router / Vuex / Axios / Element UI

CSDN - 盛洪宇(技术胖) - Vue2.x从入门到实战

创建时间:2021年7月30日
最后一次修改时间:2021年7月31日

有关于 vue 的代码是需要遵循 ESLint 规范的,本篇由于适应 MarkDown 代码块,缩进方式发生了改变,敬请谅解
ESLint 规范 - indent_style = space \n indent_size = 2
MarkDown 代码块 - indent_style = tabs \n indent_size = 4

Vue 内部指令

  • 开发版本 - 包含完整的警告和调试模式
  • 生产版本 - 删除了警告,进行了压缩
# Shell
cnpm install live-server -g
npm init # 生成 package.json 文件
live-server
  • v-if & v-else & v-show
    • v-if: 判断是否加载,可以减轻服务器的压力,在需要时加载。
    • v-show:调整css dispaly属性,可以使客户端操作更加流畅。display:none
<div id="app">
	<div v-if='isLogin'>您好:已登录</div>
	<div v-else>请登录后操作</div>
	
	<div v-show='isShow'>展示内容</div>
</div>
var app = new Vue({
	el: '#app',
	data: {
		isLogin: true,
		isShow: true
	}
})
  • v-for
<div id="app">
	<ul>
		<li v-for='item in itemsSort'>{{item}}</li>
	</ul>
	<ul>
		<li v-for='(item, index) in studentsSort'>
			{{index}} : {{item.name}} - {{item.age}}
		</li>
	</ul>
</div>
var app = new Vue({
	el: '#app',
	data: {
		items: [6, 5, 3, 7, 1, 2, 9, 8, 4],
		students: [
			{name: 'zhang', age: '23'},
			{name: 'li', age: '43'},
			{name: 'wang', age: '16'},
			{name: 'sun', age: '7'}
		]
	},
	computed: {
		itemsSort: function () {
			return this.items.sort(sortNumber)
		},
		studentsSort () {
			return sortByKey(this.students, 'age')
		}
	}
})

function sortNumber (a, b) {
	return a-b
}
function sortByKey (array, key) {
	return array.sort(function(a, b) {
		return a[key] - b[key]
	})
}
  • v-text & v-html

v-html 容易引起 xss 攻击 ,特别是不能用到表单里面

<div id="app">
	<div v-text='message'></div>
	<div v-html='dodo'></div>
</div>
var app = new Vue({
	el: '#app',
	data: {
		message: 'v-text',
		dodo: '<span style="color:red;">v-html</span>'
	}
})
  • v-on 前缀 @ 绑定事件监听器
    • click
    • keyup.键盘键值表
    • input
<div id="app">
	<p>本场比赛得分: {{fenshu}}</p>
	<div>
		<button v-on:click='add' @keyup.187='add'>加分</button>
		<button v-on:click='minus'>减分</button>
	</div>
	<input type="text" v-model='fenshu2' v-on:keyup.enter='onEnter'>
	<input type="text" v-model='fenshu2' v-on:input='onEnter'>
</div>
var app = new Vue({
	el:'#app',
	data: {
		fenshu: 0,
		fenshu2: 1
	},
	methods: {
		add: function() {
			this.fenshu++
		},
		minus: function() {
			if (this.fenshu > 0) {
				this.fenshu --
			}
		},
		onEnter: function() {
			if (this.fenshu2 > 0) {
				this.fenshu += parseInt(this.fenshu2)
			}
		}
	}
})

document.onkeydown = function(e) {
	if (e.keyCode === 187) { // 键盘键值表 187 对应 + 键
		// app.add()
	}else if(e.keyCode == 189) { //键盘键值表 189 对应 - 键
		app.minus()
	}
}
  • v-model 绑定数据源
    • 修饰符
      • .lazy:取代 input 监听 change 事件。
      • .number:输入字符串转为数字。
      • .trim:输入去掉首尾空格。
    • 特殊标签
      • input - checkbox - true/false
      • input - checkbox - Array
      • input - radio - String - value
    • input
<div id="app">
	<p>原始文本信息: {{message}}</p>
	<h4>文本框</h4>
	<div>
		<p>v-model <input type="text" id='vmodel' v-model='message'></p>
		<p>v-mode:lazy <input type="text" v-model.lazy='message'></p>
		<p>v-model:number <input type="text" v-model.number='message'></p>
		<p>v-model:trim <input type="text" v-model.trim='message'></p>
	</div>
	<h4>文本域</h4>
	<textarea cols="30" rows="4" v-model='message'></textarea>
	<h4>多选框</h4>
	<div style='user-select:none'>
		<input type="checkbox" id='sunny' v-model='sunny'>
		<label for="sunny">今天是晴天</label>&emsp;<span>sunny = {{sunny}}</span>
	</div>
	<div style='user-select:none'>
		<input type="checkbox" id='fruitApple' value='苹果' v-model='fruit'>
		<label for="fruitApple">苹果</label>
		<input type="checkbox" id='fruitBanana' value='香蕉' v-model='fruit'>
		<label for="fruitBanana">香蕉</label>
		<input type="checkbox" id='fruitOrange' value='橘子' v-model='fruit'>
		<label for="fruitOrange">橘子</label>
		<div>水果: {{fruit}}</div>
	</div>
	<h4>单选框</h4>
	<div style='user-select:none'>
		<input type="radio" id='sexMan' value='俊男爱靓女' v-model='sex' />
		<label for="sexMan">男 Man</label>
		<input type="radio" id='sexFemale' value='美女与野兽' v-model='sex' />
		<label for="sexFemale">女 Female</label>
		<div>性别: {{sex}}</div>
	</div>
	<h4>拓展: v-model & @input</h4>
	<input type="text" v-model='test' v-on:input='testInput'>
</div>
var app = new Vue({
	el: '#app',
	data: {
		message: 'hello world!',
		sunny: true,
		fruit: [],
		sex: '请选择您的喜好',
		test: null
	},
	methods: {
		testInput: function (e) {
			e.target.value = e.target.value.replace(/[^\d]/g, '')
			console.log('input:' , e.target.value)
			console.log('test:', this.test)
		}
	}
})
document.onkeydown = function (e) {
	if (document.activeElement == document.body) { // 判断当前焦点元素是否为body
		// 法一
		if (e.keyCode == 83) { // 键盘键值表 对应 s 键
			document.getElementById('sunny').click()
		}else if (e.keyCode == 49) { // 键盘键值表 对应 1 键
			document.getElementById('fruitApple').click()
		}else if (e.keyCode == 50) { // 键盘键值表 对应 2 键
			document.getElementById('fruitBanana').click()
		}else if (e.keyCode == 51) { // 键盘键值表 对应 3 键
			document.getElementById('fruitOrange').click()
		}else if (e.keyCode == 77) { // 键盘简直表 对应 m 键
			document.getElementById('sexMan').click()
		}else if (e.keyCode == 70) { // 键盘键值表 对应 f 键
			document.getElementById('sexFemale').click()
		}
		// 法二
		// let keyCodeArray = [83, 49, 50, 51, 77, 70]
		// 键盘键值表 83-s键 49-1键 50-2键 51-3键 77-m键 70-f键
		// let idArray = ['sunny', 'fruitApple', 'fruitBanana', 'fruitOrange', 'sexMan', 'sexFemale']
		// 未完待续
	}
}
  • v-bind 前缀 :
    • data 数据 小驼峰
<div id="app">
	<p><img v-bind:class='[imgBorder, imgBackground]' :src='imgSrc'></p>
	<p><a :href="aHref">首页</a></p>
	<hr>
	<div :class='[{fontRed: fontRedOK}, userSelect]'>
		<span>class 判断 数组</span>
		<input type='checkbox' id='fontRedOK' v-model='fontRedOK'>
		<label for='fontRedOK'>fontRedOK = {{fontRedOK}}</label>
	</div>
	<div :class='[fontRedOK ? fontRed : fontBlue, userSelect]'>
		<span>class 三元运算符 数组</span>
		<label>fontRedOK = <input type='checkbox' v-model='fontRedOK'>{{fontRedOK}} ? fontRed : fontBlue</label>
	</div>
	<div :style='{color: red, fontSize}'>Style</div>
	<div :style='styleObject'>Style 对象</div>
</div>
var app = new Vue ({
	el: '#app',
	data: {
		imgSrc: 'https://csdnimg.cn/release/educms/public/img/logo-small.9d4c95c9.png',
		imgBackground: 'imgBackground',
		imgBorder: 'imgBorder',
		aHref: '/',
		fontRed: 'fontRed',
		fontRedOK: true,
		userSelect: 'userSelect',
		fontBlue: 'fontBlue',
		red: 'red',
		fontSize: '20px',
		styleObject: {
			color: 'red',
			fontSize: '20px'
		}
	}
})
.imgBorder {
	border: 1px solid black;
}
.imgBackground {
	background: black;
}
.fontRed {
	color: red;
}
.fontBlue {
	color: blue;
}
.userSelect {
	user-select: none;
}
  • v-pre & v-cloak & v-once
    • v-pre 在模板中跳过vue的编译,直接输出原始值
    • v-cloak 在vue实例结束编译时从绑定的html元素上移除,经常和 display:none 配合使用
    • v-once 在第一次加载DOM时进行渲染,渲染完成后视为静态内容,跳出后续的渲染过程
<div id='app'>
	<div v-pre>{{message}}</div>
	<div v-cloak>渲染完成后,才显示!</div>
	<div v-once>{{message}} 渲染一次</div>
	<div><input type="text" v-model='message'></div>
	<div>{{message}}</div>
</div>
var app = new Vue ({
	el: '#app',
	data: {
		message: 'hello world!'
	}
})
[cloak] {
	display:none;
}

Vue 全局API

Vue内置的一些全局API
先声明全局变量或者直接在Vue上定义一些新功能
在构造器外部用Vue提供给我们的API函数来定义新的功能

  • Vue.directive 自定义指令
    • el
    • binding - rawName / name / expression / value / def
    • 生命周期(钩子函数) - bind / inserted / update /componentUpdated / unbind
<div id="app">
	<div v-color='color'>{{num}}</div>
	<p><button @click='add'>add</button></p>
	<p><button onclick='unbind()'>解绑</button></p>
</div>
function unbind() {
	app.$destroy()
}
Vue.directive('color', {
	bind: function(el, binding) {
		console.log('1 - bind');
		console.log(el);
		console.log(binding);
	},
	inserted: function() {
		console.log('2 - inserted');
	},
	update: function(el, binding) {
		console.log('3 - update');
		el.style = 'color:' + binding.value;
	},
	componentUpdated: function() {
		console.log('4 - componentUpdated');
	},
	unbind: function(el, binding) {
		console.log('5 - unbind');
		el.style = 'color: wblack';
	}
})
var app = new Vue({
	el: '#app',
	data: {
		num: 10,
		color: 'blue'
	},
	methods: {
		add: function() {
			this.num++
		}
	}
})
  • Vue.extend(option)

扩展实例构造器 预设了部分选项的Vue实例构造器
经常服务于Vue.component用来生成组件
当在模板中遇到该组件名称作为标签的自定义元素时,会自动调用“扩展实例构造器”来生产组件实例,并挂载到自定义元素上

<div id="app"></div>
<home></home>
var home = Vue.extend({
	template: '<p><a :href="homeURL">{{homeName}}</a></p>',
	data: function() {
		return {
			homeName: '首页',
			homeURL: '/'
		}
	}
})

new home().$mount('#app')
new home().$mount('home')
  • Vue.set

在构造器外部操作构造器内部的数据、属性或者方法
data 处引用构造器外部数据

外部改变数据的三种方法: Vue.set / Vue 对象 / 外部数据

由于Javascript的限制,Vue不能自动检测以下变动的数组

  • 利用索引直接设置一个项时,vue不会自动更新
  • 修改数组的长度时,vue不会自动更新
<div id="app">
	{{num}}
	<ul>
		<li v-for='item in arr'>{{item}}</li>
	</ul>
	<button onclick='add()'>修改</button>
</div>
var outData = {
	num: 10,
	arr: [10, 20, 30]
}
function add() {
	// Vue.set(outData, 'num', 20)
	// outData.num++
	app.num++
	// app.arr[1]++ // Vue可能会检测不到
	Vue.set(app.arr, 1, 40)
	// Vue.set(app.arr[1]++)
}
var app = new Vue({
	el: '#app',
	data: outData
})
  • Vue 生命周期(钩子函数)
    • 10个生命周期函数,在vue的每个阶段操作数据或者改变内容
    • beforeCreat / created
    • bedoreMount / mounted
    • beforeUpdate / updated
    • activated / deactivated
    • beforeDestroy / destroyed
<div id="app">
	{{count}}
	<p><button @click='add'>add</button></p>
	<p><button onclick='app.$destroy()'>销毁</button></p>
	<p><button @click='destroy'>销毁</button></p>
</div>
var app = new Vue({
	el: '#app',
	data: {
		count: 10
	},
	methods: {
		add: function() {
			console.log('1 - beforeAdd');
			this.count++;
			console.log('2 - added');
		},
		destroy: function() {
			this.$destroy()
		}
	},
	beforeCreate: function() {
		console.log('1 - beforeCreate');
	},
	created: function() {
		console.log('2 - created');
	},
	beforeMount: function() {
		console.log('3 - beforeMount');
	},
	mounted: function() {
		console.log('4 - mounted');
	},
	beforeUpdate: function() {
		console.log('5 - beforeUpdated');
	},
	updated: function() {
		console.log('6 - updated');
	},
	activated: function() {
		console.log('7 - activated');
	},
	deactivated: function() {
		console.log('8 - deactivated');
	},
	beforeDestroy: function() {
		console.log('9 - beforeDestroy');
	},
	destroyed: function() {
		console.log('10 - destryoed');
	},
})
  • Template 模板
    • 构造器 template 选项
    • template 标签
    • script 标签
<!-- 第一种方式 选项模板 -->
<div id="app">
	{{message}}
</div>
<!-- 第二种方式 Template 标签模板 -->
<template id='template2'>
	<h2 style='color:blue'>第二种方式 Template 标签模板</h2>
</template>
<!-- 第三种方式 Script 标签模板 -->
<script type='x-template' id='template3'>
	<h2 style='color:green'>第三种方式 Script 标签模板</h2>
</script>
<!-- <script type='x-template' id='template4' src='web文件形成一个模板'></script> -->
var template5 = `<p>This is Template5.</p>`
var app = new Vue({
	el: '#app',
	data: {
		message: 'hello world!'
	},

	// template: `
	//     <h2 style='color:red'>第一种方式 选项模板</h2>
	// `

	// template: '#template2'

	template: '#template3'

	// template: '#template4'
	
	// template: template5
})
  • Component 组件
    • 全局注册组件 - Vue.component - template
    • 局部注册组件 - components - template

自定义组件 制作自定义的标签
组件注册的是一个标签,指令注册的是标签里的一个属性

<div id="app">
	<comp1></comp1>
	<comp2></comp2>
</div>
Vue.component('comp1', {
	template: `<div style='color:red'>全局 component 组件</div>`
})
var app = new Vue({
	el: '#app',
	components: {
		'comp2': {
			template: `<div style='color:blue'>局部 component 组件</div>`
		}
	}
})
  • Component 组件 props 属性

props 选项 设置和获取标签上的属性值 小驼峰

<div id="app">
	<panda from-here='China' sex='Gentleman' v-bind:name='name'></panda>
</div>
var app = new Vue({
	el: '#app',
	data: {
		name: 'xiaoPan'
	},
	components: {
		'panda': {
			template: `
				<p style='color:blue'>panda is {{fromHere}} , sex is {{sex}} , name is {{name}}.</p>
			`,
			props: ['fromHere', 'sex', 'name']
		}
	}
})
  • Component 父子组件
<div id="app">
	<panda></panda>
</div>
var cityComponent = {
	template: `<p style='color:blue'>SiChuan in China.</p>`
}
var pandaComponent = {
	template: `
		<div>
			<p style='color:red'>panda from china.</p>
			<city></city>
		</div>
	`,
	components: {
		'city': cityComponent
	}
}
var app = new Vue({
	el: '#app',
	components: {
		'panda': pandaComponent
	}
})
  • Component 标签
<div id="app">
	<component :is='who'></component>
	<p><button @click='changeComponent'>change component</button></p>
</div>
var componentA = {
	template: `<p style='color:red'>This is componentA</p>`
}
var componentB = {
	template: `<p style='color:blue'>This is componentB</p>`
}
var componentC = {
	template: `<p style='color:green'>This is componentC</p>`
}
var app = new Vue({
	el: '#app',
	data: {
		who: 'componentA'
	},
	components: {
		'componentA': componentA,
		'componentB': componentB,
		'componentC': componentC
	},
	methods: {
		changeComponent: function () {
			if (this.who == 'componentA') {
				this.who = 'componentB'
			} else if (this.who == 'componentB') {
				this.who = 'componentC'
			} else if (this.who == 'componentC') {
				this.who = 'componentA'
			}
		}
	}
})

Vue 选项操作

  • propsData
<header></header>
var header = Vue.extend({
	template: `<p>{{message}} {{a}}</p>`,
	data: function() {
		return {
			message: 'hello world!'
		}
	},
	props: ['a']
})

new header({
	propsData:{
		a:10
	}
}).$mount('header')
  • computed
    • get 默认
    • set

computed和methods的区别
computed与methods的异同
Vue中computed和methods的区别
vue中computed和methods区别
深入理解配置选项之data和methods| 重学Vue3

区别methodscomputed
响应式非响应式响应式
第一次调用页面加载时系统运行时
执行跟随data实例值变化而执行数值发生变化时
返回值可写可不写视为一个变量值
以对象的属性方式存在的,在视图层直接调用就可以得到值
调用methods定义的成员必须以函数形式调用,视为一个方法computed定义的成员像属性一样访问,视为一个变量值
缓存每次调用时都要执行缓存值不变,不会重新调用(其引用的响应式属性发生改变时才会重新计算)
<div id="app">
	{{newPrice}}
	<ol>
		<li v-for='item in reverseNews'>{{item.title}} - {{item.data}}</li>
	</ol>
</div>
var newsList = [
	{title: 'news1', data: '2021-1'},
	{title: 'news2', data: '2021-2'},
	{title: 'news3', data: '2021-3'},
	{title: 'news4', data: '2021-4'}
]
var app = new Vue({
	el: '#app',
	data: {
		price: 100,
		newsList: newsList
	},
	computed: {
		newPrice: function () {
			return '人民币' + this.price + '元' 
		},
		reverseNews: function () {
			return this.newsList.reverse()
		}
	}
})
  • Methods
    • $event 点击鼠标的一些事件和属性
    • native 给组件绑定构造器里的原生事件

vue @click.native和@click.stop和@click.self

<div id="app">
	{{count}}
	<p><button @click='add(10, $event)'>add</button></p>
	<p><btn @click.native='add(50)'></btn></p>
</div>
<p><button onclick='app.add(100)'>外部 add</button></p>
var btn = {
	template: `<button>组件 原生 add</button>`
}
var app = new Vue({
	el: '#app',
	data: {
		count: 10
	},
	components: {
		'btn': btn
	},
	methods: {
		add: function (num, event) {
			if (num > 0) {
				this.count += num;
			} else {
				this.count++;
			}
			console.log(event);
		}
	}
})
  • Watch
<div id="app">
	<p>今日温度: {{temperature}}℃</p>
	<p>穿衣建议: {{clothing}}</p>
	<p style='user-select:none'>
		<button @click='add'>增加温度</button>
		<button @click='minus'>减少温度</button>
	</p>
</div>
var app = new Vue({
	el:'#app',
	data: {
		temperature: 15,
		clothing: '夹克长裙'
	},
	methods: {
		add: function () {
			this.temperature += 5;
		},
		minus: function () {
			this.temperature -= 5;
		}
	},
	// 构造器
	watch: {
		temperature: function (newVal, oldVal) {
			if (newVal > 26) {
				this.clothing = 'T恤短袖'
			} else if (newVal > 1) {
				this.clothing = '夹克长裙'
			} else {
				this.clothing = '棉衣羽绒服'
			}
		}
	}
})
// 实例属性
// app.$watch('temperature', function (newVal, oldVal) {})
  • Mixins
    • 已经写好了构造器,需要增加方法或者临时使用的方法,用混入会减少源代码的污染
    • 很多地方都会用到的公用方法,用混入的方法可以减少代码量,实现代码重用
    • 调用先后顺序: 方法 (有原生方法只执行原生方法) | 生命周期 (全局 Vue.mixin - mixins - 原生)
<div id="app">
	{{num}}
	<p><button @click='add'>add</button></p>
</div>
var addConsole = {
	updated: function () {
		console.log('数据发生变化 , num = ' + this.num)
	},
	created: function () {
		console.log('created')
	}
}
Vue.mixin({
	updated: function () {
		console.log('全局 updated , num = ' + this.num)
	},
	created: function () {
		console.log('全局 created')
	}
})
var app = new Vue({
	el: '#app',
	data: {
		num: 10
	},
	methods: {
		add: function () {
			this.num++
		}
	},
	updated: function () {
		console.log('原生 updated , num = ' + this.num)
	},
	created: function () {
		console.log('原生 created')
	},
	mixins: [addConsole]
})
  • Extends
    • 执行顺序: 方法 (有原生只执行原生方法,否则执行扩展方法) | 生命周期 (扩展 - 原生)
    • delimiters - 改变插值的符号
<div id="app">
	${num}
	<p><button @click='add'>add</button></p>
</div>
var extendsObj = {
	methods: {
		add: function () {
			this.num++;
			console.log('扩展 methods');
		}
	},
	updated: function () {
		console.log('扩展 updated');
	}
}
var app = new Vue({
	el: '#app',
	data: {
		num: 10
	},
	methods: {
		add: function () {
			this.num++;
			console.log('原生 methods');
		}
	},
	updated: function () {
		console.log('原生 updated');
	},
	extends: extendsObj,
	delimiters: ['${', '}']
})

Vue 实例和内置组件

  • 属性
<script src='https://code.jquery.com/jquery-3.6.0.min.js'></script>
<div id="app">
	{{message}}
</div>
var app = new Vue({
	el:'#app',
	data: {
		message: 'hello world!'
	},
	methods: {
		add: function() {
			console.log('构造器内部的add方法。');
		}
	},
	mounted: function() {
		$('#app').html('我是 JQuery!'); // jQuery 需要引入jQuery
	}
})
app.add();
  • 方法
    • $mount - 挂载扩展
    • $destroy - 卸载
    • $forceUpdate - 更新
    • $nextTick - 数据修改,相当于一个钩子函数,和构造器里的updated生命周期很像
<div id="app"></div>
<p><button onclick='del()'>$destroy</button></p>
<p><button onclick='update()'>$forceUpdate</button></p>
<p><button onclick='tick()'>$nextTick</button></p>
var ex = Vue.extend({
	template: `<p>{{message}}</p>`,
	data: function() {
		return {
			message: 'hello world!'
		}
	},
	mounted: function() {
		console.log('mounted');
	},
	updated: function() {
		console.log('updated');
	},
	destroyed: function() {
		console.log('destroyed');
	}
})
var e = new ex().$mount('#app');
function del() {
	e.$destroy();
}
function update() {
	e.$forceUpdate();
}
function tick() {
	e.message = 'this is Vue!';
	e.$nextTick(function() {
		console.log('$nextTick');
	})
}
  • 事件
    • 在构造器外部调用构造器内部的数据
    • $on - 在构造器外部添加事件
    • $once - 执行一次的事件
    • $off - 关闭事件
<div id="app">
	{{num}}
	<p><button @click='add'>add</button></p>
</div>
<p><button onclick='minus()'>minus</button></p>
<p><button onclick='once()'>once</button></p>
<p><button onclick='off()'>off</button></p>
var app = new Vue({
	el:'#app',
	data: {
		num: 10
	},
	methods: {
		add: function() {
			this.num++;
		}
	}
})
app.$on('minus', function() {
	this.num--;
})
app.$once('once', function() {
	this.num = 50;
})
function minus() {
	app.$emit('minus');
}
function once() {
	app.$emit('once');
}
function off() {
	app.$off('minus')
}
  • 内置组件 slot
    • 标签的内容扩展,在自定义组件时传递给组件内容,组件接收内容并输出
<div id="app">
	<net>
		<span slot='url'>{{net.url}}</span>
		<span slot='name'>This is name.</span>
		<span slot='skill'>{{net.skill}}</span>
	</net>
</div>
<template id='net'>
	<div>
		<p>url: <slot name='url'></slot></p>
		<p>name: <slot name='name'></slot></p>
		<p>skill: <slot name='skill'></slot></p>
	</div>
</template>
var net = {
	template: `#net`
}
var app = new Vue({
	el: '#app',
	data: {
		net: {
			url: 'This is netUrl.',
			name: 'This is name.',
			skill: 'This is Vue.'
		},
		num: 10
	},
	components: {
		'net': net
	}
})

Vue-cli

cnpm install vue-cli -g # -g 全局安装

vue init <template-name> <project-name> # 初始化项目
# <template-name>
# webpack | webpack-simple | browserify | browserify-simple | simple

vue init webpack vueCliTest
cd vueCliTest

cnpm install # 安装 package.json 依赖包 node_modules
# build 项目构建 webpack
# config 项目开发环境配置
# node_modules npm包管理器
# src 源码目录
# static 静态文件目录

# /src/main.js 整个项目的入口文件
# /src/router/index.js 路由文件

npm run dev # 开发 | package.json - scripts - dev
npm run build # 生产 | 生成 dist 目录
# dev | start | build 打包
# /.editorconfig
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

Vue-router

# 终端
npm list -g --depth 0 # 查看通过npm安装的包
cnpm install vue-cli -g # 淘宝镜像 cnpm 安装脚手架 vue-cli
vue init webpack vueCliTest # 初始化 vue 项目
cd vueCliTest
cnpm install vue-router --dev-save # 安装路由 vue-router
cnpm install # 如果 packgae.json 添加了新的插件与版本,可以使用此命令自动安装
npm run dev # 运行开发环境
# 修改启动端口 默认 8080
# /config/index.js - module.exports - dev - port
// /src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld' // /src/components/HelloWorld.vue
import Hi from '@/components/Hi'
import Hi1 from '@/components/Hi-1'
import Hi2 from '@/components/Hi-2'
import params from '@/comoponents/params'
import ErrorPage from '@/components/ErrorPage'

Vue.use(Router) // 全局使用

export default new Router({
	mode: 'history', // history / hash 默认值,项目打包上线需要改回 hash 模式,否则容易出错
	routes: [ // 路由 数组
		{ // 每个链接是一个对象
			path: '/', // 链接路径
			name: 'HelloWorld', // 路由名称
			// component: HelloWorld // 组件模板
			components: { // 单页面多路由区域操作 对象
				default: HelloWorld, // 默认路由
				left: Hi1, // 对应 router-view - name='left'
				right: Hi2 // 对应 router-view - name='right'
			}
		},
		{
			pth: '/Hi',
			name: 'Hi',
			component: Hi,
			children: [ // 子路由 数组
				{path: 'Hi-1', name: 'Hi-1', component: Hi1},
				{path: 'Hi-2', name: 'Hi-2', component: Hi2}
			]
		},
		{
			path: '/params/:id(\\d+)/:title', // 利用 url 传递参数 id(\\d+) 正则表达式
			name: 'params',
			component: params,
			beforeEnter: (to, from, next) => { // 路由中的钩子函数
				console.log('index.js', to) // to 路由将要跳转的路径信息,信息包含在对象里
				console.log('index.js', from) // from 路由跳转前的路径信息,信息包含在对象里
				next() // next 路由的控制参数 常用的有 next(true) next(false)
				// next({path: '/'})
			}
		}{
			path: '/goHome',
			redirect: '/' // 重定向
		},
		{
			path: '/goParams/:id(\\d+)/:title',
			redirect: '/params/:id(\\d+)/:title' // 重定向时传递参数
		},
		{
			path: '/',
			alias: '/aliasHome' // alias 实现类似重定向的效果 注意不能跳转到首页
		},
		{
			path: '*',
			name: 'ErrorPage',
			component: ErrorPage // 404 页面
		}
	]
}
<!-- /src/App.vue -->
<template>
	<div id="app">
		<!-- 编程式导航 -->
		<div>
			<button @click='goBack'>后退</button>
			<button @click='goForward'>前进</button>
			<button @click='goHome'>首页</button>
		</div>

		<div>
			<router-link to="/">首页</router-link> | <!-- router-link 导航 to 链接路径 显示名称 -->
			<router-link to="/Hi">Hi</router-link> |
			<!-- <router-link to="/Hi/Hi-1">Hi-hi1<router-link> |-->
			<!-- <router-link to="{name: xxx, params: {key: value}}">valueString</router-link> -->
			<router-link :to="{name: 'Hi-1', params: {id: 1, name: 'Hi-1'}}">Hi-1</router-link> |
			<router-link to="/Hi/Hi-2">Hi-2<router-link> |
			<!-- 利用url传递参数 -->
			<router-link to='/params/2/Welcome to params page!'>params</router-link> |
			<!-- 重定向 -->
			<router-link to='goHome'>goHome<router-link> |
			<!-- 重定向时传递参数 -->
			<router-link to='/goParams/3/I like Vue.js'>goParams</router-link> |
			<!-- alias 实现类似重定向的效果 注意不能跳转到首页 -->
			<router-link to='/aliasHome'>aliasHome</router-link>
			<!-- 任何未在 index.js 有过明确定义的 url ,都会进入 404 页面 ErrorPage.vue -->
			<router-link to='/xxxx'>ErrorPage<router-link>
		</div>

		<!-- transtion name='fade' class='fade-enter fade-enter-active fade-leave fade-leave-active' -->
		<transition name='fade' mode='in-out'>
			<router-view></router-view>
			<!-- 单页面多路由区域操作 -->
			<router-view name='left' style='float:left;width:50%;height:300px;background:#ccc;'></router-view>
			<router-view name='right' style='float:right;width:50%;height:300px;background:#ddd;'></router-view>
		</transition>
	</div>
</template>

<script>
export default {
	name: 'App',
	methods: {
		goBack: function () {
			this.$router.go(-1) // 后退
		},
		goForward: function () {
			this.$router.go(1) // 前进
		},
		goHome: function () {
			this.$router.push('/') // 导航到首页
		}
	}
}
</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;
}
.fade-enter {
	opacity: 0;
	position: relative;
	right: 100vw;
}
.fade-enter-active {
	transition-property: all;
	transition-duration: 4s;
	transition-timing-function: ease-out;
}
.fade-enter-to {
	opacity: 1;
	position: relative;
	right: 0;
}
.fade-leave {
	opacity: 1;
}
.fade-leave-active {
	transition-property: opacity;
	transition-duration: 2s;
}
.fade-leave-to {
	opacity: 0;
}
</style>
<!-- /src/components/Hi.vue -->
<template>
	<div class='hello'>
		<h1>{{message}}</h1>
		<hr>
		<router-view></router-view>
	</div>
</template>

<script>
export default {
	name: 'Hi',
	data () {
		return {
			message: 'This is Hi page.
		}
	}
}
</script>
<!-- /src/components/Hi-1.vue -->
<template>
	<div class='hello'>
		<h1>{{message}}</h1>
		<hr>
		<p>{{$route.name}}</p>
		<p>id: {{$route.params.id}}</p>
		<p>name: {{$route.params.name}}</p>
	</div>
</template>

<script>
export default {
	name: 'Hi-1',
	data () {
		return {
			message: 'This is Hi-1 page.
		}
	}
}
</script>

<style scoped>
</style>
<!-- /src/components/Hi-2.vue -->
<template>
	<div>
		<h2>{{msg}}</h2>
	</div>
</template>

<script>
export default {
	name:'Hi-2',
	data () {
		return {
			msg: 'This is Hi-2 page!'
		}
	}
}
</script>
<!-- /src/components/params.vue -->
<template>
	<div>
		<h2>{{msg}}</h2>
		<p>id: {{$route.params.id}}</p>
		<p>title: {{$route.params.title}}</p>
	</div>
</template>
<script>
export default {
	name: 'params',
	data () {
		return {
			msg: 'This is params page!'
		}
	},
	// 模板中的钩子函数
	beforeRouteEnter: (to, from, next) => { // 路由进入前的钩子函数
		console.log('params.vue', '准备进入 params 路由模板')
		next()
	},
	beforeRouterLeave: (to, from, next) => { // 路由离开前的钩子函数
		consol.log('params.vue', '准备离开 params 路由模板')
		next()
	}
},
</script>
<!-- /src/components/Errorpage.vue -->
<template>
	<div>
		<h2>{{msg}}</h2>
	</div>
</template>

<script>
export default {
	name: 'ErrorPage',
	data () {
		return {
			msg: 'Error: 404 page!'
		}
	}
}
</script>
modehashhistory
URL协议://域名/#/路由协议://域名/路由
页面刷新不会出现404错误会出现404错误
vue路由mode模式:history与hash的区别
vue中mode hash 和 history的区别
重定向redirectalias
路由path: 'goHome', redirect: '/'path: '/Hi', alias: '/aliasHi'
导航<router-link to='goHome'>goHome</router-link><router-link to='aliasHi'>aliasHi</router-link>
path:'/'可以跳转不能跳转

<transition name='fade'>CSS过渡类名
fade-enter:进入过渡的开始状态,元素被插入时生效,只应用一帧后立刻删除。
fade-enter-active:进入过渡的结束状态,元素被插入时就生效,在过渡过程完成后移除。
fade-leave:离开过渡的开始状态,元素被删除时触发,只应用一帧后立刻删除。
fade-leave-active:离开过渡的结束状态,元素被删除时生效,离开过渡完成后被删除。

Vuex 单页状态管理

cnpm install vuex --save # 利用 npm 包管理工具 安装 vuex 生产环境 --save 版本位置 package.json - dependencies
// /src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import helloWorld from '@/components/HelloWorld'
import Count from '@/components/Count'

Vue.use(Router)

export default new Router({
	mode: 'history',
	routes: [
		{
			path: '/',
			name: 'HelloWorld',
			component: HelloWorld
		},
		{
			path: '/Count',
			name: 'Count',
			component: Count
		}
	]
})
<template>
	<nav>
		<a href='/'>首页</a>
		<a href='/Count'>Count</a>
		<a href='goBack'>后退</a>
		<a href='goForward'>前进</a>
	</nav>

	<router-view></router-view>

	{{route.name}}
</template>

<script>
export default {
	name: 'App',
	methods: {
		goBack: function () {
			this.$router.go(-1)
		},
		goForward: function () {
			this.$router.go(1)
		}
	}
}
</script>

<style scope>
#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;
}
a {
	cursor: pointer;
	color: blue;
	text-decoration: underline;
}
a, button {
	user-select: none;
}
</style>
// /src/vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
	count: 1
}

const mutations = {
	add: function (state, n = 1) {
		state.count += n
	},
	reduce: function (state, n = 1) {
		state.count -= n
	}
}

const getters = { // 计算过滤操作
	count: function (state) {
		state.count += 0
		return state.count
	}
}

const actions = { // 异步修改状态
	addAction (context) { // context 上下文独享
		context.commit('add', 10)
		setTimeout(() => { // 异步检验
			context.commit('reduce')
		}, 2000)
		console.log('我比 reduce 先执行')
	},
	reduceAction ({commit}) { // {commit}
		commit('reduce')
	}
}

const moduleA = { // 声明模块组
	state,
	mutations,
	getters,
	actions
}

export default new Vuex.Store({ // 封装代码 让外部可以引用
	modules: {
		a: moduleA
	}
})
<!-- /src/components/Count.vue -->
<template>
	<div>
		<h2>{{msg}}</h2>
		<p>$store.state.count: {{$store.state.count}}</p>
		<p>count(): {{count}}</p>
		<p>
			<button @click="$store.commit('add', 10)">addCount</button>
			<button @click="reduce()">reduceCount</button>	
		</p>
		<p>
			<button @click='addAction'>addAction</button>
			<button @click='reduceAction'>reduceAction</button>
		</p>
	</div>
</template>

<script>
import stroe from '@/vuex/store'
import { mapState, mapMutations, mapGetters, mapActions } from 'vuex'

export default {
	name: 'Count',
	data () {
		return {
			msg: 'Hello Vuex!'
		}
	},
	// 法一 访问状态对象
	// computed: {
	//   count: function () {
	//     return this.$store.state.count
	//   }
	// },
	
	// 法二 访问状态对象
	// computed: mapState({
	//   count: function (state) {
	//     return state.count
	//   }
	// }),
	
	// 法三 访问状态对象
	// computed: mapState({
	//   count: state => state.count
	// }),
	
	// 法四 访问状态对象
	// computed: mapState(['count']),
	computed: {
		...mapState(['count']), // 访问状态对象 扩展运算符
		// count: function () {
		//   return this.$store.state.count
		// }
		...mapGetters(['count']) // 计算过滤操作 扩展运算符
		// count () {
		//   return this.$store.a.count
		// }
	},
	// methods: mapMutations(['add', 'reduce']),
	methods: {
		...mapMutations(['add', 'reduce']), // 修改状态 扩展运算符
		...mapActions(['addAction', 'reduceAction']) // 异步修改状态 扩展运算符
	},
	store
}
</script>

实战

  • Mockplus 把我们的想法画出来

技术栈 - Vue + Webpack + Element + Axios + vueRouter
内容 - 快餐店的POS系统 收银模块
Vue - 主体
Webpack - 打包程序 构建工具
Element - UI 界面
Axios - 数据请求 后端交互
vueRouter - 路由系统
MockPlus 慕课 软件 免费
幕客 产品 Mockplus经典版

  • Vue-cli 搭建开发环境
npm list -g --depth 0
cnpm install vue-cli -g
vue -V
vue init webpack # 已经有目录,在目录下可以省略项目名称
# Vue build - standalone | vue-router | ESLint
cnpm install
npm run dev
<style scoped>/* scoped 局部变量,只在当前模板生效 */</style>
  • 搞定项目图标 Iconfont

Font Awesome
Google Play 图标设计规范
iconfont
图标库 - 官方图标库 - 天猫图标库 碎蜂
汉堡 店铺 购买 功能建议 会员卡 - 添加至项目 Pos - Font class
Unicode 非语义化 | Font class 语义化 | Symbol

<i class='icon iconfont icon-dianpu'></i>
<i class='icon iconfont icon-huiyuanqia'></i>
  • 开启 Element 封印

Element 组件库
Element

# 项目目录下
cnpm install element-ui --save # --save 生产环境
npm run dev
  • 利用 Element 快速布局

多标签栏 订单栏

  • Axios 从远程读取数据
cnpm install axios  --save
  • 项目打包和上线

/config/index.js - module.exports - build - assetsPublicPath: ‘./’
/build/utils.js - 51 column - options.extract - publicPath: ‘…/…/’
cnpm run build

附录

Vue全家桶介绍
× 失效 技术胖 – Vue2.x学习路线-按次路线学习顺畅无比
技术胖 – 视频教程
CSDN 视频 – Vue2.x从入门到实战
博客园 – noticeable - 键盘键值对应表

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inkScholar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值