Vue练手项目

小记

这里有篇讲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>

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于github上的vue3 ts练手项目,我了解到有一个使用了node、koa、ts和mongodb搭建了接口服务的todoList项目项目中使用了vue3全家桶和vant组件库,并且结合了ElementPlus组件库进行项目实战。学习这个项目,你将会学到vue3的项目实战使用、setup等新增语法的使用,以及对vue3的支持和ElementPlus的使用。同时还包括了工程化管理项目的书写规范、提交风格等方面的内容。此外,还有如何封装vuex中的mapgetters,封装网络请求,以及如何正确地根据项目结构化来划分ts项目的综合使用等内容。你可以在github上下载这个项目并在本地运行。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [vue3+ts+ElementPlus 实战项目 musicPlus](https://blog.csdn.net/kzj0916/article/details/123161883)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [简单易上手的vue3.0+ts实战小项目!!附带后台接口](https://blog.csdn.net/qq_44812835/article/details/113195479)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值