Vue的学习经历
Vue简介
相关链接
VSCode官网
vue.js官网
axiso官网
axiso下载链接
vue.router官网
vue-router.js下载链接
免费Http请求测试数据链接
animate.css官网
bootstrap官网
bootstrap-4.3.1下载链接
Node.js 安装包及源码下载链接
webpack官网
OpenIconic图标官网
MUI下载链接
码云项目代码托管平台
vee-validate官网
vue-layzload官网
vuejs-dialog官网
Vue开发环境搭建
VSCode与插件安装
- Express
- HTML Snippets
- Bootstrap v4 Snippets
- One Dark Pro
- Preview on Web Server
- TabOut
- vscode-icons
- Vue 2 Snippets
- vue-beautify
Chrome插件安装
- Vue.js devtools
Node.js及webpack相关安装
- 下载Node.js 的window安装包并安装
- 安装完成后打开cmd输入: node --version
- 安装nrm,cmd输入 : npm install -g nrm
- 查看镜像,输入: nrm ls
- cmd输入: nrm use cnpm
- webpack、webpack-cli、webpack-dev-server全局安装,cmd输入:
npm install webpack webpack-cli webpack-dev-server -g
- 检查安装结果与版本号
用户自定义代码段快捷键
- 打开设置界面:File -> Preferences ->User Snippets
- 选择html.json
- 粘贴下面的代码段保存即可
{
"vh":{
"prefix": "vh",
"body": [
"<!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>Document</title>",
" <script src=\"./lib/vue.js\"></script>",
"</head>",
"",
"<body>",
" <div id=\"app\">",
"",
" </div>",
"",
" <script>",
" var vm = new Vue({",
" el: '#app',",
" data: {",
" },",
" methods: {",
" }",
" })",
" </script>",
"</body>",
"",
"</html>"
]
}
}
.vue后缀文件启用html语法补全
- 按F1,输入settings.json并选择Open Settings(JSON)
- 在settings.json中添加files.associations,内容如下
{
"files.associations": {
"*.vue":"html"
}
}
Vue上手
vue对象实例
- el:指定要控制的区域
- data:是一个对象,指定控制区域内要用的到的数据
- methods:是一个对象,方法集,可以自定义方法
- VM实例中,如果要访问data上的数据,或者要访问methods中的方法,必须使用this
<script>
new Vue({
el: '#app',
data: {
msg: 'world',
},
methods: {
show:function(){
alert("hello")
}
},
})
</script>
基本指令
- 插值表达式和v-text
- v-cloak
- v-html
- v-bind 属性绑定 缩写是:
- v-on 事件绑定 缩写是@
- v-model 数据双向绑定
Vue生命周期钩子
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
Vue练习案例
基本指令练习
<!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>Document</title>
<script src="./lib/vue.js"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<!-- 使用v-cloak能够解决 插值表达式闪烁的问题 -->
<p v-cloak>{{ msg }}</p>
<h4 v-text="msg"></h4>
<div v-html="msg2"></div>
<!-- v-bind:是Vue中提供用于绑定属性的指令 -->
<!-- v-bind:可以简写为 : -->
<input type="button" value="按钮" v-bind:title="mytitle + '123'" id="btn">
<input type="button" value="按钮" :title="mytitle + '123'" v-on:click="show">
<!-- v-model:可以实现表单元素与Model中数据的双向绑定 -->
<input type="text" v-model="msg">
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'world',
msg2: '<h1>html元素添加</h1>',
mytitle: '这是自定义title'
},
methods: {
show:function(){
alert("hello")
}
},
})
</script>
</body>
</html>
事件修饰符
- .stop
- .prevent
- .capture
- .self
- .once
<!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>Document</title>
<script src="./lib/vue.js"></script>
<style>
.inner {
height: 150px;
background-color: darkcyan;
}
.outer {
padding: 40px;
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 使用.stop阻止冒泡 -->
<div class="inner" @click="divInnerHandler">
<input type="button" value="点击我" @click.stop="btnHandler">
</div>
<!-- 使用.prevent阻止默认行为 -->
<a href="http://www.baidu.com" @click.prevent="linkClick">有问题,问百度(阻止默认行为)</a>
<!-- 使用.capture实现捕获触发事件 -->
<div class="inner" @click.capture="divInnerHandler">
<input type="button" value="点击我" @click="btnHandler">
</div>
<!-- 使用.once 只触发一次事件-->
<a href="http://www.baidu.com" @click.prevent.once="linkClick">有问题,问百度(阻止默认行为且只触发一次)</a>
<!-- 使用.self 实现只有点击当前元素时才触发事件,只会阻止自己冒泡,不阻止其他元素的冒泡-->
<div class="outer" @click="divOuterHandler">
<div class="inner" @click.self="divInnerHandler">
<input type="button" value="点击我" @click="btnHandler">
</div>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
},
methods: {
btnHandler() {
console.log("你触发了 btn 按钮 点击事件");
},
divInnerHandler() {
console.log("你触发了 inner 按钮 点击事件");
},
divOuterHandler() {
console.log("你触发了 outer 按钮 点击事件");
},
linkClick() {
console.log("你触发了 link 点击事件");
}
}
})
</script>
</body>
</html>
Vue中的样式
<!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>Document</title>
<script src="./lib/vue.js"></script>
<style>
.red {
color: red;
}
.thin {
font-weight: 200;
}
.italic {
font-style: italic;
}
.active {
letter-spacing: 0.5em;
}
</style>
</head>
<body>
<div id="app">
<!-- 这里的class需要使用v-bind做数据绑定 -->
<h1 :class="['red','thin', flag?'active':'']">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :class="['red','thin', {active:flag}]">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :class="{red:false, thin:true, italic:false, active:false}">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :class="classObj">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :style="{color:'red','font-size':'40px'}">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :style="styleObj1">这是一个很大的H1,通过绑定class来改变我的样式</h1>
<h1 :style="[styleObj1,styleObj2]">这是一个很大的H1,通过绑定class来改变我的样式</h1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: true,
classObj: {red:false, thin:true, italic:false, active:false},
styleObj1: {color:'red','font-size':'40px'},
styleObj2: {'font-style': 'italic'}
},
methods: {
}
})
</script>
</body>
</html>
v-for / v-if / v-show
*v-for 注意使用key属性
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 遍历数组 -->
<!-- <p v-for="(item,i) in list">索引值:{{i}} --- id:{{item.id}} --- 名字:{{item.name}}</p> -->
<!-- 遍历对象键值对 -->
<!-- <p v-for="(val,key,i) in user">值:{{val}} --- 键:{{key}} --- 索引:{{i}}</p> -->
<!-- 迭代数字 count从1开始-->
<!-- <p v-for="count in 6">这是第{{count}}此循环</p> -->
<div>
<label>Id:
<input type="text" v-model="id">
</label>
<label>Name:
<input type="text" v-model="name">
</label>
<input type="button" value="添加" @click="add">
</div>
<!-- v-for循环时,key属性只能使用number或string -->
<!-- key属性必须使用v-bind绑定,指定key的值 -->
<p v-for="item in list" :key="item.id">
<input type="checkbox">
{{item.name}}
</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
id:'',
name:'',
list: [
{ id: 1, name: '萧薰儿' },
{ id: 2, name: '小医仙' },
{ id: 3, name: '美杜莎' },
{ id: 4, name: '云韵' },
{ id: 4, name: '雅妃' },
],
user: {
id: 1,
name: '萧炎',
gender: '男'
},
flag
},
methods: {
add(){
this.list.unshift({id:this.id, name:this.name})
}
}
})
</script>
</body>
</html>
过滤器的基本用法
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ msg | msgFormat('邪恶') | append('!!!')}}</p>
</div>
<div id="app2">
<p>{{ msg | msgFormat('疯狂') | append('!!!')}}</p>
</div>
<script>
//定义全局过滤器
Vue.filter('msgFormat', function (msg, arg) {
// 方法1
// return msg.replace('单纯','邪恶')
// 方法2:正则
return msg.replace(/单纯/g, arg)
})
Vue.filter('append', function (msg, arg) {
return msg + arg;
})
var vm = new Vue({
el: '#app',
data: {
msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的人'
},
methods: {
}
})
var vm2 = new Vue({
el: '#app2',
data: {
msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的人'
},
methods: {},
filters: {
// 定义私有过滤器,[过滤器名称:处理函数]
// 过滤器调用时采用就近原则,如果私有过滤器和全局过滤器重名,优先调用私有过滤器
msgFormat: function (msg, arg) {
return msg.replace(/单纯/g, arg) + '~~~'
}
}
})
</script>
</body>
</html>
跑马灯效果
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="浪起来" @click="lang">
<input type="button" value="低调" @click="stop">
<h4>{{msg}}</h4>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '猥琐,别浪~~! ',
intervalId: null
},
methods: {
lang() {
if (this.intervalId != null) return;
this.intervalId = setInterval(() => {
var start = this.msg.substring(0, 1)
var end = this.msg.substring(1)
this.msg = end + start;
}, 100)
},
stop() {
clearInterval(this.intervalId)
this.intervalId = null;
}
},
})
</script>
</body>
</html>
简易计算器
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" @click="calc">
<input type="text" v-model="result">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
n1: 0,
n2: 0,
result: 0,
opt: '+'
},
methods: {
calc() {
switch (this.opt) {
case '+':
this.result = parseInt(this.n1) + parseInt(this.n2)
break;
case '-':
this.result = parseInt(this.n1) - parseInt(this.n2)
break;
case '*':
this.result = parseInt(this.n1) * parseInt(this.n2)
break;
case '/':
this.result = parseInt(this.n1) / parseInt(this.n2)
break;
default:
break;
}
//取巧方式
// var codeStr = 'parseInt(this.n1)' + this.opt + 'parseInt(this.n2)'
// this.result = eval(codeStr);
}
}
})
</script>
</body>
</html>
axios基本使用
<!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>Document</title>
<script src="./lib/vue.js"></script>
<script src="./lib/axios.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="get请求" @click="getInfo">
<input type="button" value="post请求" @click="postInfo">
</div>
<script>
var http = axios.create({
baseURL: 'http://jsonplaceholder.typicode.com'
})
var vm = new Vue({
el: '#app',
data: {
},
methods: {
getInfo() {
// 不带参数
http.get('users').then(function (response) {
console.log(response)
}).catch(function (response) {
console.log(response)
})
// 带参数
http.get('users', { params: { username: 'test' } }).then(function (response) {
console.log(response)
}).catch(function (response) {
console.log(response)
})
},
postInfo() {
http.post('users', { username: 'test', password: 123456 }).then(function (response) {
console.log(response)
}).catch(function (response) {
console.log(response)
})
}
}
})
</script>
</body>
</html>
品牌列表案例
<!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>Document</title>
<script src="./lib/vue.js"></script>
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body>
<div id="app">
<div class="card">
<div class="card-header">
<span v-fontweight="900" v-fontsize="'30px'">添加品牌</span>
</div>
<div class="card-body form-inline">
<label>Id:
<input type="text" class="form-control" v-model="id">
</label>
<label>Name:
<!-- 使用按钮修饰符 -->
<input type="text" class="form-control" v-model="name" @keyup.enter="add">
</label>
<input type="button" value="添加" class="btn btn-primary" @click="add">
<label>搜索名称关键字:
<input type="text" class="form-control" v-model="keywords" v-focus v-color="'blue'">
</label>
</div>
</div>
<table class="table table-light table-bordered table-hover table-striped">
<thead class="thead-light">
<tr>
<th>Id</th>
<th>Name</th>
<th>Ctime</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr v-for="item in search(keywords)" :key="item.id">
<td>{{item.id}}</td>
<td v-text="item.name"></td>
<td>{{ item.ctime | DateFormat }}</td>
<td>
<a href="" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<script>
//定义全局过滤器
Vue.filter('DateFormat', function (DateStr, pattern = "") {
var dt = new Date(DateStr)
var y = dt.getFullYear()
var m = (dt.getMonth() + 1).toString().padStart(2, '0')
var d = (dt.getDate()).toString().padStart(2, '0')
if (pattern.toLowerCase() === 'yyy-mm-dd') {
return `${y}-${m}-${d}`
} else {
var hh = (dt.getHours()).toString().padStart(2, '0')
var mm = (dt.getMinutes()).toString().padStart(2, '0')
var ss = (dt.getSeconds()).toString().padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
})
//自定义按键修饰符,对应键码
Vue.config.keyCodes.f2 = 113
//自定义全局指令v-focus,使用Vue.directive()
//参数1:指令名称,定义时不需要加v-前缀,调用时需要加v-前缀
//参数2:对象,指令相关函数集,在特定阶段执行相关函数
Vue.directive('focus', {
//注:每个函数中第一个参数永远是el,表示被绑定指令的那个原生js对象
bind: function (el) { //每当指定绑定到元素上时,会立即执行bind函数,且只触发一次
},
inserted: function (el) { //当元素插入到DOM中时,会执行inserted函数,且只触发一次
el.focus()
},
updated() { //当VNode更新时,会执行updated,可能会触发多次
},
})
Vue.directive('color', {
bind: function (el, binding) {
el.style.color = binding.value
},
inserted: function () {
},
updated() {
},
})
//创建Vue实例对象
var vm = new Vue({
el: '#app',
data: {//自定义变量
id: '',
name: '',
keywords: '',//搜索关键字
list: [
{ id: 1, name: '宝马', ctime: new Date() },
{ id: 2, name: '奔驰', ctime: new Date() },
{ id: 3, name: '奥迪', ctime: new Date() },
]
},
methods: {//自定义方法
add() {
var car = { id: this.id, name: this.name, ctime: new Date() }
this.list.push(car)
this.id = this.name = ''
},
del(id) {
// 方法1
// this.list.some((item,i) =>{
// if(item.id == id){
// this.list.splice(i,1)
// return true;
// }
// })
// 方法2
var index = this.list.findIndex(item => {
if (item.id == id) {
return true;
}
})
this.list.splice(index, 1);
},
search(keywords) {
var newList = [];
// 方法1
// this.list.forEach(item => {
// //字符串匹配:是否包含字符串
// if (item.name.indexOf(keywords) != -1) {
// newList.push(item)
// }
// });
// 方法2
newList = this.list.filter(item => {
if (item.name.includes(keywords)) {
return item
}
})
return newList;
}
},
filters: {//自定义私有过滤器
DateFormat: function (DateStr, pattern = "") {
var dt = new Date(DateStr)
var y = dt.getFullYear()
var m = (dt.getMonth() + 1).toString().padStart(2, '0')
var d = (dt.getDate()).toString().padStart(2, '0')
if (pattern.toLowerCase() === 'yyy-mm-dd') {
return `${y}-${m}-${d}`
} else {
var hh = (dt.getHours()).toString().padStart(2, '0')
var mm = (dt.getMinutes()).toString().padStart(2, '0')
var ss = (dt.getSeconds()).toString().padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
}
},
directives: {//自定义私有指令
'fontweight': { //设置字体粗细
bind: function (el, binding) {
el.style.fontWeight = binding.value
}
},
'fontsize': function (el, binding) { //注:此写法等同把代码写到bind和update函数中
el.style.fontSize = parseInt(binding.value) + 'px'
}
}
})
</script>
</body>
</html>
过渡动画实现
<!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>Document</title>
<script src="./lib/vue.js"></script>
<link rel="stylesheet" href="./css/animate.css">
<style>
.my-enter,
.my-leave-to {
opacity: 0;
transform: translateY(150px);
}
.my-enter-active,
.my-leave-active {
transition: all 0.5s ease;
}
.ball {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: red;
}
li {
border: 1px dashed #999999;
margin: 5px;
line-height: 35px;
padding-left: 5px;
font-size: 12px;
width: 100%
}
li:hover {
background-color: cornflowerblue;
transition: all 0.3s ease;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateY(70px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
.v-move {
transition: all 0.5s ease;
}
.v-leave-active {
position: absolute;
}
</style>
</head>
<body>
<div id="app">
<input type="button" value="自定义过渡动画触发" @click="show = !show">
<transition name="my">
<h3 v-if="show">H3 动画</h3>
</transition>
<hr>
<input type="button" value="第三方过渡动画触发" @click="show2 = !show2">
<transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter:200, leave:400}">
<h6 class="animated" v-if="show2">H6 动画</h6>
</transition>
<input type="button" value="自定义小球半场动画触发" @click="showBall = !showBall">
<transition @before-Enter="beforeEnter" @enter="enter" @after-Enter="afterEnter">
<div class="ball" v-show="showBall"></div>
</transition>
<input type="button" value="自定义列表添加元素动画触发" @click="add">
<!-- 为v-for循环创建的元素设置动画必须为每个元素设置:key属性 -->
<!-- 为transition-group添加appear属性,实现页面初始入场效果 -->
<!-- 为transition-group设置tag属性,指定其渲染为特定元素,默认渲染为span标签 -->
<transition-group appear tag="ul">
<li v-for="(item,i) in list" :key="item.id" @click=del(i)>
{{item.id}} --- {{item.name}}
</li>
</transition-group>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true,
show2: true,
showBall: true,
count: 1,
name: '名字',
list: [
{ id: 1, name: "名字" }
]
},
methods: {
beforeEnter(el) {
el.style.transform = "translate(0,0)"
},
enter(el, done) {
el.offsetWidth
el.style.transform = "translate(150px, 450px)"
el.style.transition = 'all 1s ease'
done()
},
afterEnter(el) {
this.showBall = !this.showBall
},
add() {
//自增id
this.count = this.count + 1
var item = { id: this.count, name: this.name }
this.list.push(item)
},
del(i) {
this.list.splice(i, 1)
}
}
})
</script>
</body>
</html>
组件创建使用与传值
<!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>Document</title>
<script src="./lib/vue.js"></script>
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.3s ease;
}
</style>
</head>
<body>
<div id="app">
<globalcom></globalcom>
<!-- 父组件向子组件传递方法使用v-on事件绑定机制 -->
<privatecom v-bind:parentmsg="msg" @func="show"></privatecom>
<hr>
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- compontent是一个占位符,:is属性可以用来指定要展示的组件名称 -->
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
<template id="globaltemp">
<div>
<input type="button" value="+1" @click="increment">
<h3>{{count}}</h3>
</div>
</template>
<template id="privatetemp">
<div>
<h1>这是私有template元素 子组件 --- {{parentmsg}}</h1>
<input type="button" value="子组件按钮,触发父组件传递的func方法" @click="subclick">
</div>
</template>
<script>
//定义全局组件
Vue.component('globalcom', {
template: '#globaltemp',
data: function () {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
})
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
msg: '父类数据',
msgfromson: null,
comName: 'login'
},
methods: {
show(param1, param2) {
msgfromson = param2
console.log('调用了父组件的show方法---' + param1)
}
},
components: {
privatecom: {
template: '#privatetemp',
// props中的数据只读
props: ['parentmsg'],
// data中的数据可读可写
data() {
return {
title: '标题',
content: '内容',
sonmsg: { name: '井底之蛙', age: 6 }
}
},
methods: {
subclick() {
this.$emit('func', 123, this.sonmsg)
}
}
}
}
})
</script>
</body>
</html>
使用ref获取DOM元素与组件
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="ref获取" ref="mybtn" @click="getref">
<h3 ref="myh3">我是h3,请通过ref来获取我的数据</h3>
<hr>
<login ref="mylogin"></login>
</div>
<script>
var login = {
template: '<h1>登录组件</h1>',
data() {
return {
msg: '组件数据'
}
},
methods: {
show(){
console.log('调用了组件方法')
}
},
}
var vm = new Vue({
el: '#app',
data: {
},
methods: {
getref() {
console.log(this.$refs.myh3.innerText);
console.log(this.$refs.mylogin.msg);
this.$refs.mylogin.show()
}
},
components: {
'login': login
}
})
</script>
</body>
</html>
组件案例-评论列表
<!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>Document</title>
<script src="./lib/vue.js"></script>
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body>
<div id="app">
<cmt-box @func="loadComments"></cmt-box>
<ul class="list-group">
<li class="list-group-item" v-for="(item,index) in list" :key="index">{{item.content}}
<span class="badge badge-secondary">评论人:{{item.user}}</span>
</li>
</ul>
</div>
<template id="tmp1">
<div>
<div class="form-group">
<label>评论人:</label>
<input class="form-control" type="text" v-model="user">
</div>
<div class="form-group">
<label>评论内容:</label>
<input class="form-control" type="text" v-model="content">
</div>
<div class="form-group">
<button class="btn btn-primary" type="button" @click="submit">提交评论</button>
</div>
</div>
</template>
<script>
var vm = new Vue({
el: '#app',
data: {
list: [
{ user: '萧炎', content: '我最爱的人是药老' },
{ user: '美杜莎', content: '异火的味道很不错' },
{ user: '云韵', content: '等级再高也挡不住爱情' }
]
},
created() {
this.loadComments()
},
methods: {
loadComments() {
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
this.list = list
}
},
components: {
'cmt-box': {
template: '#tmp1',
data() {
return {
user: '',
content: '',
}
},
methods: {
submit() {
var comment = { 'user': this.user, 'content': this.content }
//从localstrage中获取所有的评论
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
list.unshift(comment)
localStorage.setItem('cmts', JSON.stringify(list))
this.user = this.content = ''
this.$emit('func')
}
}
}
}
})
</script>
</body>
</html>
watch监视及computed计算属性
<!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>Document</title>
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="firstname">
+
<input type="text" v-model="lastname">
=
<input type="text" v-model="fullname">
=
<input type="text" v-model="fullnamecomputed">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
firstname: '',
lastname: '',
fullname: ""
},
methods: {
},
watch: {//监视data中指定数据的变化,然后出发这个watch中对应的function函数
'firstname': function (newVal, oldVal) {
this.fullname = newVal + '-' + this.lastname
},
'lastname': function (newVal) {
this.fullname = this.firstname + '-' + newVal
}
},
computed: {//计算属性,本质是一个方法,不过使用时直接当做属性来使用而不当作方法调用
//function内求值结果会被缓存起来,所用到的任何data中的数据发生变化都会立即重新求值
'fullnamecomputed': function () {
return this.firstname + '-' + this.lastname
}
}
})
</script>
</body>
</html>
路由的使用
<!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>Document</title>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<style>
.router-link-active,
.myactive {
color: red;
font-weight: 800;
font-size: 30px;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease
}
</style>
</head>
<body>
<div id="app">
<!-- router-link默认渲染为a标签,如果需要改变可以是用tag来指定 -->
<router-link to="/account" tag="span">用户</router-link>
<router-view></router-view>
</div>
<template id="accounttemp">
<div>
<h1>Account组件</h1>
<!-- <router-link to="/login?id=9&name=sc">登录</router-link> -->
<!-- 第1种路由传参方式 -->
<router-link to="/account/login/9/sc">登录</router-link> <!-- 第2种路由传参方式 -->
<router-link to="/account/register">注册</router-link>
<transition mode="out-in">
<router-view></router-view>
</transition>
</div>
</template>
<script>
var account = {
template: '#accounttemp'
}
var login = {
// template: '<h1>登录组件 --- {{$route.query.id}} --- {{$route.query.name}}</h1>',//第1种路由传参方式
template: '<h1>登录组件 --- {{$route.params.id}} --- {{$route.params.name}}</h1>',//第2种路由传参方式
created() {
// console.log(this.$route.query.id);//第1种路由传参方式
console.log(this.$route.params.id);//第2种路由传参方式
},
}
var register = {
template: '<h1>注册组件</h1>'
}
const router = new VueRouter({
routes: [//路由规则
// 每个路由规则都是一个对象,这个规则对象有两个必须属性
// 属性1:path,表示监听哪个路由链接地址
// 属性2:component,表示对应path的展示组件,注意他的值必须是一个组件模板对象,不能是组件的引用名称
{ path: '/', redirect: '/account' },//根路径重定向到login
{
path: '/account',
component: account,
// 路由嵌套
children: [
// { path: '/login', component: login },//第1种路由传参方式
{ path: 'login/:id/:name', component: login }, //第2种路由传参方式
{ path: 'register', component: register },
]
},
],
linkActiveClass: 'myactive' //自定义激活类名
})
var vm = new Vue({
el: '#app',
data: {
},
methods: {
},
router, //将路由规则对象注册到vm实例上
watch: { //监视路由的地址改变
'$route.path': function (newVal, oldVal) {
if (newVal.indexOf('/account/login') != -1) {
console.log('欢迎进入登录界面');
} else if (newVal.indexOf('/account/register') != -1) {
console.log('欢迎进入注册界面');
}
}
}
})
</script>
</body>
</html>
路由命名视图实现经典布局
<!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>Document</title>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
}
h1 {
margin: 0;
padding: 0;
font-size: 20px;
}
.header {
background-color: orange;
height: 80px;
}
.container {
display: flex;
height: 600px;
}
.left {
background-color: lightgreen;
flex: 2;
}
.main {
background-color: lightpink;
flex: 8;
}
</style>
</head>
<body>
<div id="app">
<!-- router-view的name属性值默认为default -->
<router-view></router-view>
<div class="container">
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
</div>
<script>
var header = {
template: '<h1 class="header">Header头部区域</h1>'
}
var leftBox = {
template: '<h1 class="left">Left侧边栏区域</h1>'
}
var mainBox = {
template: '<h1 class="main">MainBox主体区域</h1>'
}
const router = new VueRouter({
routes: [
{
path: '/', components: {
'default': header,
'left': leftBox,
'main': mainBox
}
}
]
})
var vm = new Vue({
el: '#app',
data: {
},
methods: {
},
router
})
</script>
</body>
</html>
使用webpack
mkdir webpack-study
cd webpack-demo
mkdir dist
mkdir src
- 使用VSCode打开webpack-study文件夹
- 在src目录下创建index.html与index.js
- VSCode中使用快捷键 ctrl+` 打开终端输入:
//生成package.json文件
npm init -y
//因项目中用了jquery改变样式,所以安装jquery
npm i jquery -S
//安装html-webpack-plugin,可自动把html打包到内存,并为html添加bundle.js引用
npm i html-webpack-plugin -D
//如是全局安装webpack,在项目使用html-webpack-plugin,需要项目安装webpack
npm install webpack
//安装css样式加载器
npm i style-loader css-loader -D
//安装url加载器
npm i url-loader file-loader -D
//安装bootstrap 4.3.1及open-iconic字体图标库
npm i bootstrap -S
cnpm i open-iconic -D
//安装babel
npm i babel-core babel-loader babel-plugin-transform-runtime -D
npm i babel-preset-env babel-preset-stage-0 -D
//如报升级问题:npm i babel-loader@7 -D
- 项目src目录下新建文件index.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>Document</title>
<!-- 已在配置文件plugin中使用htmlWebpackPlugin处理 -->
<!-- <script src="/bundle.js"></script> -->
<!-- 已在配置文件module中使用style-loader,css-loader处理 -->
<!-- <link rel="stylesheet" href="./css/index.css"> -->
</head>
<body>
<ul>
<li>第1个li</li>
<li>第2个li</li>
<li>第3个li</li>
<li>第4个li</li>
<li>第5个li</li>
<li>第6个li</li>
<li>第7个li</li>
</ul>
<div class="box"></div>
<span class="oi oi-account-login" aria-hidden="true"></span>
<span class="oi oi-account-logout" aria-hidden="true"></span>
</body>
</html>
- 项目src目录下新建文件index.js
//导入Jquary, import * from * 是ES6中的导入模块的方式
import $ from 'jquery'
//使用import语法导入css样式表
//webpack默认只能打包处理js类型文件,如要处理非js类型文件则需手动安装第三方 loader加载器
//需要在配置文件中的添加module对象的rules属性
import './css/index.css'
//引入node_modules中相关文件可以直接写包的名称接具体文件路径
import 'bootstrap/dist/css/bootstrap.css'
import 'open-iconic/font/css/open-iconic-bootstrap.css'
$(function () {
$('li:odd').css('backgroundColor', 'blue')
$('li:even').css('backgroundColor', function () { return '#654321' })
})
class Person {
static info = { name: 'scrat', age: 30 }
}
console.log(Person.info)
- 项目src下的css目录里新建文件index.css
html,body{
margin: 0;
padding: 0;
}
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
/* 默认webpack无法处理url地址 */
.box{
width: 200px;
height: 100px;
background: url('../images/火柴人.jpg');
background-size: cover;
}
- 项目根目录下新建文件**.babelrc**
{
"presets":["env","stage-0"],
"plugins": ["transform-runtime"]
}
- 项目根目录下新建配置文件webpack.config.js,内容如下:
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase: path.join(__dirname, 'src'),
port: 9000,
inline: true,
compress: true,
open: true,
},
plugins: [
new htmlWebpackPlugin({
template: path.join(__dirname, './src/index.html'),
filename: 'index.html'
})
],
module: { //用于配置第三方模块加载器
rules: [ //所有模块的匹配规则
//配置处理.css文件的第三方loader规则,use列表处理流程从右到左
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
//处理url路径的loader规则
//默认图片base64处理,limit=限制文件字节数
//若以url图片名显示默认名会hash处理,name=hash值8位 + 原名 + 原后缀
{ test: /\.(jpg|jpeg|png|gif|bmp)$/, use: 'url-loader?limit=20000&name=[hash:8]-[name].[ext]' },
//字体文件的匹配规则
{ test: /\.(ttf|eot|svg|woff|woff2|otf)$/, use: 'url-loader' },
//Babel配置
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
]
},
performance: {
hints: false
}
}
- 使用web-dev-server启动
npm run dev