Vue练手项目

tech2024-11-06  10

这里写目录标题

小记笔记一、项目初始化1、初始化2、安装webpack3、引入并使用vue Webpack的基本配置基本配置文件配置loader 写几个小栗子栗子一栗子二栗子三栗子四栗子五 练手实例

小记

这里有篇讲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.jscompiler only的文件 compiler.jsruntime + 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>

最新回复(0)