小记
这里有篇讲Vue的博客,挺不错的,参考:
https://blog.csdn.net/qq_44317018/article/details/104146747
笔记
一、项目初始化
1、初始化
首先使用vscode快捷键打开当前文件夹下的命令行
Ctrl + `
运行
npm init -y
生成package.json文件
在项目中需要用到webpack进行打包,下面安装webpack
2、安装webpack
执行
npm install webpack webpack-cli -D
其中-D是 --save-dev的简写,表示开发环境依赖
3、引入并使用vue
首先对项目进行基本配置
创建index.html、main.js等
配置Vue环境
npm install vue
配置完成后在node_modules文件夹下回多出一个vue文件夹,并且在package.json中会多出vue依赖
Webpack的基本配置
基本配置文件
//导入path模块
const path=require('path')
module.exports={
//打包入口
entry:'./src/main.js',
//打包出口
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
}
}
在package.json中添加脚本指令
现在打包执行下面的指令即可
npm run build
配置loader
vue-loader官方文档:https://vue-loader.vuejs.org/
loader的官方文档:https://www.webpackjs.com/loaders/
执行:
npm install -D vue-loader vue-template-compiler
注意:需要额外单独安装 css-loader
执行:
npm install -D css-loader
npm install style-loader --save-dev
配置webpack配置文件:
//导入path模块
const path=require('path')
const { Plugin } = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports={
//打包入口
entry:'./src/main.js',
//打包出口
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
//打包规则
module:{
rules:[
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
//插件配置
plugins:[
new VueLoaderPlugin()
]
}
报错:
You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
解释:
Vue会打包生成三个文件:
- runtime only文件 vue.common.js
- compiler only的文件 compiler.js
- runtime + compiler 的文件 vue.js
默认导出:vue.common.js
在webpack中添加 别名的配置:
resolve:{
alias:{
'vue':'vue/dist/vue.js'
}
}
写几个小栗子
栗子一
实现效果:
跑通,代码如下:
Test.vue:
<template>
<div>
<button id="btn_add" @click="add_num()">+</button>
<h2 id="num">{{num}}</h2>
<button id="btn_del" @click="del_num()">-</button>
</div>
</template>
<script>
export default {
name:"test",
data:function () {
return{
num:0
}
},
methods:{
add_num:function () {
console.log(123);
this.num++;
},
del_num:function () {
this.num--;
}
}
}
</script>
main.js:
import Vue from 'vue'
import test from './Test.vue'
const app=new Vue({
el: '#app',
components:{
test
},
template:`<test/>`
})
栗子二
实现效果:
代码如下:
Test2.vue:
<template>
<div>
<h1>用户名:{{name}}</h1>
<h2>性别:{{sex==1?"男" :"女"}}</h2>
<h3>下单时间:{{new Date().toLocaleDateString()}}</h3>
<h3>小计:¥{{(price*count).toFixed(2)}}</h3>
<input v-model="name" type="text">
<input type="radio" id="male" value="1" v-model="sex" name="sex">男
<input type="radio" id="male" value="0" v-model="sex" name="sex">女
</div>
</template>
<script>
export default {
name:"test2",
data:function() {
return{
name:"张三",
sex:"1",
orderTime:"1579507293225",
price:12.5,
count:5
}
}
}
</script>
这里讲过复选框等基础控件的v-modal的用法:
https://blog.csdn.net/lzl980111/article/details/104740163
栗子三
实现效果:
练习v-if
代码如下:
Test3.vue
<template>
<div>
<h2 v-if="isLogin">已登录</h2>
<a @click="login()">登录</a>
<a @click="exit()">注销</a>
</div>
</template>
<script>
export default {
name:"test3",
data:function(){
return{
isLogin:false
}
},
methods:{
login:function () {
this.isLogin=true
},
exit:function () {
this.isLogin=false
}
}
}
</script>
这里使用v-show也是可以实现的,v-show是加入了display:none这个css样式,而v-if是直接删除dom,相比的话v-if效率会低一些
栗子四
观察者模式
实现效果:
代码如下:
Test4.vue:
<!--
观察者(observer)模式:
当变量修改时,所有观察者都会自动接收到通知,并受到新值
-->
<template>
<div>
<h1>Message:{{message_now}}</h1>
<input v-model="message_now" v-focus>
<br>
<button @click="addObv()">添加观察者</button>
<br>
<button @click="publish_message()">发布</button>
<ul>
<li v-for="(item,index) in observers" :key='index'>
<h2>观察者姓名:{{item.name}}</h2>
<h3>观察者信息:{{item.message}}</h3>
</li>
</ul>
</div>
</template>
<script>
export default {
name:"test4",
data:function(){
return {
message_now:"123",
observers:[
{
name:"obv1",
message:"321",
getNewMessage:function(){
this.message=message_now
}
}
],
}
},
methods:{
//定义addObv方法用来添加观察者
addObv:function(){
console.log("测试添加观察者");
const obverser={
name:"obv",
message:this.message
};
this.observers.push(obverser);
console.log("观察者添加完成");
},
//定义publish_message方法用来发布信息
publish_message:function(){
this.observers.forEach(observer=>{
observer.item="obv",
observer.message=this.message_now
})
},
}
}
</script>
main.js:
import Vue from 'vue'
import test4 from './Test4.vue'
/**
* 此处应用自定义指令,在相应的控件上添加对应指令即可应用
* 例:v-focus
*/
Vue.directive("focus",{
inserted(domElem){
//让当前元素自动获得焦点
domElem.focus();
}
})
const app=new Vue({
el: '#app',
components:{
test4
},
template:`<test4/>`
})
上面还用到了自定义指令,自动聚焦到文本框
栗子五
购物车
效果:
代码如下:
Test5.vue
<template>
<div>
<div v-if="books.length">
<table>
<thead>
<tr>
<th></th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>数量</th>
<th>操作</th>
</tr>
</thead>
<tr v-for="(item,index) in books" :key="index">
<td>{{item.id}}</td>
<td>{{item.bookname}}</td>
<td>{{item.pubdate}}</td>
<td>{{item.price | showPrice}}</td>
<td>
<button @click="decrement(index)" v-bind:disabled="item.count<=1">-</button>
{{item.count}}
<button @click="increment(index)" >+</button>
</td>
<td><button @click="del(index)">移除</button></td>
</tr>
<tbody></tbody>
</table>
<h2>总价格:{{sum}}</h2>
</div>
<h2 v-else>购物车为空</h2>
</div>
</template>
<script>
export default {
name:"test5",
data:function(){
return{
books:[
{id:1,bookname:'计算机网络',pubdate:'2006-9',price:15.00,count:1},
{id:2,bookname:'操作系统',pubdate:'2016-9',price:20.00,count:1},
{id:3,bookname:'JavaSE程序设计',pubdate:'2012-9',price:35.00,count:1},
{id:4,bookname:'PHP程序设计',pubdate:'2010-9',price:42.00,count:1},
]
}
},
methods:{
increment:function(index){
console.log('---------increment'+index)
this.books[index].count++;
},
decrement:function(index){
//if (this.books[index].count==0) return;
console.log('---------decrement'+index)
this.books[index].count--;
},
del:function(index){
this.books.splice(index,1);
}
},
filters:{
/**
* 过滤器语法格式:
* (1). 绑定语法中: {{变量 | 过滤器1 |过滤器2 | … }}
(2). 强调:
a. 后一个过滤器2,进入的旧值,已经不是变量的原始值了,而是前一个过滤器加工后的中间值。
b. 只有最后一个过滤器的返回值,才会显示到页面上。如果希望前几个过滤器的返回值也能一起显示到页面上,只能在最后一个过滤器中将新值拼接到上一步过滤器传入的旧值上。
*/
showPrice(price){
return '¥'+price.toFixed(2)
}
},
computed:{
/**
* computed区别于methods
* computed(计算属性)
* (1). 只要计算属性所依赖的另一个属性值发生改变,同样会通知计算属性重新计算新的属性值。
(2). 计算属性计算出的结果,会被Vue缓存起来,反复使用,避免重复计算。即使反复使用多次,也只在首次计算一次。
-------区别--------
(1). 用法:
a. methods必须加()
b. computed 不用加()
(2). 反复使用:
a. methods中的方法,每调用一次,就会重新执行一次,执行结果,不会被vue缓存起来。
b. computed中的计算属性,只在第一次使用时计算一次,然后,结算结果,就会被Vue缓存起来,即使在别的地方反复使用这个计算属性,也不会重复计算,而是直接从缓存中获取值。但是,当所依赖的其他属性值发生变化时,计算才被迫重新计算一次。
如何选择methods和computed:
(1). 如果这次使用时,更关心函数的执行结果数据时,首选计算属性
(2). 如果这次使用时,更关心函数执行操作的过程,结果数据无所谓,甚至函数没有返回值,则首选methods中的方法。
*
*/
sum:{
get(){
let sum=0;
for (let book of this.books){
sum+=book.count*book.price;
}
return sum+'¥';
}
}
}
}
</script>
<style scoped>
table{
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th, td{
padding: 8px 16px;
border:1px solid #e9e9e9;
text-align: left;
}
th{
background-color: #f7f7f7;
color: #5c6b77;
font-weight:600;
}
</style>
练手实例
<!DOCTYPE html>
<!--[if IE 9 ]><html class="ie9"><![endif]-->
<head>
<!-- bootstrap是一个响应式布局,分辨率做自适应
initial-scale=1 缩放比例,完全不缩放
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<meta name="format-detection" content="telephone=no">
<meta charset="UTF-8">
<meta name="description" content="Violate Responsive Admin Template">
<meta name="keywords" content="Super Admin, Admin, Template, Bootstrap">
<style>
hr{
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top-color: currentcolor;
border-top-style: none;
border-top-width: 0px;
border-top: 1px solid #eee;
}
</style>
</head>
<body id="skin-blur-violate">
<title>Vue练习</title>
<div id="app">
<p>{{name}}</p>
<p>计算属性:{{sum}};计算属性是基于它们的响应式依赖进行缓存的,若num1或num2没有发生改变,再次获取sum是直接获取到而不需要执行其中的方法,区别于methods</p>
<p>{{fullName}}</p>
<hr>
<p>请输入问题:</p>
<input v-model="question">
<p>{{answer}}</p>
<div v-bind:class="{active:isActive}"></div>
<h1 v-if="isActive">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
<button @click="changeActive()">改变isActive</button>
<ul>
<li v-for="(item,index) in books">
{{item}}
</li>
</ul>
<input v-on:keyup.13="enterdown" placeholder="回车监听" v-model="book">
<hr>
<h2>model与各个控件之间的使用</h2>
<p>{{textmessage}}</p>
<input type="text" v-model="textmessage">
<hr>
<p style="white-space: pre-line;">{{textareamessage}}</p>
<textarea name="" id="" cols="30" rows="10" v-model="textareamessage"></textarea>
<hr>
<p>{{checkboxmessage}}</p>
<input type="checkbox" v-model="checkboxmessage">
<hr>
<p>{{checkedmessage}}</p>
<input type="checkbox" value="西游记" v-model="checkedmessage"><label>西游记</label>
<input type="checkbox" value="三国演义" v-model="checkedmessage"><label>三国演义</label>
<input type="checkbox" value="水浒传" v-model="checkedmessage"><label>水浒传</label>
<input type="checkbox" value="红楼梦" v-model="checkedmessage"><label>红楼梦</label>
<hr>
<p>{{sex==1 ? '男' : '女'}}</p>
<input type="radio" v-model="sex" value="1"><label>男</label>
<input type="radio" v-model="sex" value="0" checked><label>女</label>
<hr>
<p>{{selected|selected}}</p>
<select v-model="selected">
<option value="1">西游记</option>
<option value="2">三国</option>
<option value="3">鲁滨逊</option>
</select>
<hr>
</div>
</body>
<script src="./vue.js"></script>
<script>
const app=new Vue({
el:"#app",
data:{
name:"张三",
num1:1,
num2:2,
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar',
question:'',
answer:'I cannot give you an answer until you ask a question!',
isActive:false,
books:["海贼王","JAVA","三国"],
book:'',
textmessage:'textmessage',
textareamessage:'textareamessage',
checkboxmessage:true,
checkedmessage:[],
sex:'性别',
selected:''
},
computed:{
sum:function(){
return this.num1+this.num2
},
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
},
},
methods:{
changeActive:function(){
if(this.isActive){
this.isActive=false;
}else{
this.isActive=true;
}
},
enterdown:function(){
this.books.push(this.book);
}
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
},
question:function(newque,oldque){
console.log("测试quest");
this.answer='Waiting for you to stop typing...';
},
books:function(){
console.log("测试数组");
}
},
filters:{
selected:function(value){
switch(value){
case '1':
return '西游记';
break;
case '2':
return '三国'
break;
case '3':
return '鲁滨逊'
break;
}
}
}
})
</script>
</html>