vue使用mammoth案例_vue快速入门的三个小实例

本文是关于Vue.js的入门教程,通过三个实际的小项目——选项卡、统计总价和文字编辑,帮助读者逐步了解和掌握Vue的基础用法。文章详细介绍了每个实例的实现原理和代码,适合已具备HTML、CSS和JavaScript基础的读者学习。通过实践,读者可以更好地理解和运用Vue的数据绑定、事件处理等核心特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.前言

用vue做项目也有一段时间了,之前也是写过关于vue和webpack构建项目的相关文章,大家有兴趣可以去看下webpack+vue项目实战(一,搭建运行环境和相关配置)(这个系列一共有5篇文章,这是第一篇,其它几篇文章链接就不贴了)。但是关于vue入门基础的文章,我还没有写过,那么今天就写vue入门的三个小实例,这三个小实例是我刚接触vue的时候的练手作品,难度从很简单到简单,都是入门级的。希望能帮到大家更好的学习和了解vue,也是让自己能够复习一下vue。如果发现文章写得有什么不好,写错了,或者有什么建议!欢迎大家指点迷津!

1.本篇文章使用的vue版本是2.4.2,大家要注意版本问题

2.现在我也是假设您有基础的html,css,javascript的知识,也已经看过了官网的基本介绍,对vue有了一个大概的认识了,了解了常用的vue指令(v-model,v-show,v-if,v-for,v-on,v-bind等)!如果刚接触前端的话,你看着文章可能会蒙圈,建议先学习基础,掌握了基础知识再来看!

3.下面的实例,建议大家边看文章边动手做!这样思路会非常清晰,不易混乱!也不会觉得文章长!如果只看文章,你可能未必会看完,因为文章我讲得比较细,比较长!

4.这几个实例,摘自我自己的平常练习的项目,代码已经提到github上面了(vue-demos)。欢迎大家star。!

2.什么是vue

vue是现在很火的一个前端MVVM框架,它以数据驱动和组件化的思想构建,与angular和react并称前端三大框架。相比angular和react,vue更加轻巧、高性能、也很容易上手。大家也可以移步,看一下vue的介绍和核心功能官网介绍。简单粗暴的理解就是:用vue开发的时候,就是操作数据,然后vue就会处理,以数据驱动去改变DOM(不知道有没有理解错,理解错了指点下)。

下面就是一个最简单的说明例子

代码如下

html

{{ message }}

js

new Vue({

el: '#app',

data: {

message: 'Hello Vue!'

}

})

相信也不难理解,就是input绑定了message这个值,然后在input修改的时候,message就改了,由于双向绑定,同时页面的html({{ message }})进行了修改!

好,下面进入例子学习!

3.选项卡

运行效果

原理分析和实现

这个很简单,无非就是一个点击切换显示而已。但是大家也要实现。如果这个看明白了,再看下面两个!这个实例应该只是一个热身和熟悉的作用!

这个的步骤只有一步,原理也没什么。我直接在代码打注释,看了注释,大家就明白了!

完整代码

Title

body{

font-family:"Microsoft YaHei";

}

#tab{

width: 600px;

margin: 0 auto;

}

.tab-tit{

font-size: 0;

width: 600px;

}

.tab-tit a{

display: inline-block;

height: 40px;

line-height: 40px;

font-size: 16px;

width: 25%;

text-align: center;

background: #ccc;

color: #333;

text-decoration: none;

}

.tab-tit .cur{

background: #09f;

color: #fff;

}

.tab-con div{

border: 1px solid #ccc;

height: 400px;

padding-top: 20px;

}

html

css

javascript

vue

html

css

javascript

vue

new Vue({

el: '#tab',

data: {

curId: 0

},

computed: {},

methods: {},

mounted: function () {

}

})

4.统计总价

运行效果

原理分析和实现

首先,还是先把布局写好,和引入vue,准备vue实例,这个不多说,代码如下

Title

.fl{

float: left;

}

.fr{

float: right;

}

blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul {

margin: 0;

padding: 0;

}

.clearfix{

zoom: 1;

}

.clearfix:after {

clear: both;

}

.clearfix:after {

content: '.';

display: block;

overflow: hidden;

visibility: hidden;

font-size: 0;

line-height: 0;

width: 0;

height: 0;

}

a{

text-decoration: none;

color: #333;

}

img{vertical-align: middle;}

.page-shopping-cart {

width: 1200px;

margin: 50px auto;

font-size: 14px;

border: 1px solid #e3e3e3;

border-top: 2px solid #317ee7; }

.page-shopping-cart .cart-title {

color: #317ee7;

font-size: 16px;

text-align: left;

padding-left: 20px;

line-height: 68px; }

.page-shopping-cart .red-text {

color: #e94826; }

.page-shopping-cart .check-span {

display: block;

width: 24px;

height: 20px;

background: url("shopping_cart.png") no-repeat 0 0; }

.page-shopping-cart .check-span.check-true {

background: url("shopping_cart.png") no-repeat 0 -22px; }

.page-shopping-cart .td-check {

width: 70px; }

.page-shopping-cart .td-product {

width: 460px; }

.page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total {

width: 160px; }

.page-shopping-cart .td-do {

width: 150px; }

.page-shopping-cart .cart-product-title {

text-align: center;

height: 38px;

line-height: 38px;

padding: 0 20px;

background: #f7f7f7;

border-top: 1px solid #e3e3e3;

border-bottom: 1px solid #e3e3e3; }

.page-shopping-cart .cart-product-title .td-product {

text-align: center;

font-size: 14px; }

.page-shopping-cart .cart-product-title .td-check {

text-align: left; }

.page-shopping-cart .cart-product-title .td-check .check-span {

margin: 9px 6px 0 0; }

.page-shopping-cart .cart-product {

padding: 0 20px;

text-align: center; }

.page-shopping-cart .cart-product table {

width: 100%;

text-align: center;

font-size: 14px; }

.page-shopping-cart .cart-product table td {

padding: 20px 0; }

.page-shopping-cart .cart-product table tr {

border-bottom: 1px dashed #e3e3e3; }

.page-shopping-cart .cart-product table tr:last-child {

border-bottom: none; }

.page-shopping-cart .cart-product table .product-num {

border: 1px solid #e3e3e3;

display: inline-block;

text-align: center; }

.page-shopping-cart .cart-product table .product-num .num-do {

width: 24px;

height: 28px;

display: block;

background: #f7f7f7; }

.page-shopping-cart .cart-product table .product-num .num-reduce span {

background: url("shopping_cart.png") no-repeat -40px -22px;

display: block;

width: 6px;

height: 2px;

margin: 13px auto 0 auto; }

.page-shopping-cart .cart-product table .product-num .num-add span {

background: url("shopping_cart.png") no-repeat -60px -22px;

display: block;

width: 8px;

height: 8px;

margin: 10px auto 0 auto; }

.page-shopping-cart .cart-product table .product-num .num-input {

width: 42px;

height: 28px;

line-height: 28px;

border: none;

text-align: center; }

.page-shopping-cart .cart-product table .td-product {

text-align: left;

font-size: 12px;

line-height: 20px; }

.page-shopping-cart .cart-product table .td-product img {

border: 1px solid #e3e3e3;

margin-right: 10px; }

.page-shopping-cart .cart-product table .td-product .product-info {

display: inline-block;

vertical-align: middle; }

.page-shopping-cart .cart-product table .td-do {

font-size: 12px; }

.page-shopping-cart .cart-product-info {

height: 50px;

line-height: 50px;

background: #f7f7f7;

padding-left: 20px; }

.page-shopping-cart .cart-product-info .delect-product {

color: #666; }

.page-shopping-cart .cart-product-info .delect-product span {

display: inline-block;

vertical-align: top;

margin: 18px 8px 0 0;

width: 13px;

height: 15px;

background: url("shopping_cart.png") no-repeat -60px 0; }

.page-shopping-cart .cart-product-info .product-total {

font-size: 14px;

color: #e94826; }

.page-shopping-cart .cart-product-info .product-total span {

font-size: 20px; }

.page-shopping-cart .cart-product-info .check-num {

color: #333; }

.page-shopping-cart .cart-product-info .check-num span {

color: #e94826; }

.page-shopping-cart .cart-product-info .keep-shopping {

color: #666;

margin-left: 40px; }

.page-shopping-cart .cart-product-info .keep-shopping span {

display: inline-block;

vertical-align: top;

margin: 18px 8px 0 0;

width: 15px;

height: 15px;

background: url("shopping_cart.png") no-repeat -40px 0; }

.page-shopping-cart .cart-product-info .btn-buy {

height: 50px;

color: #fff;

font-size: 20px;

display: block;

width: 110px;

background: #ff7700;

text-align: center;

margin-left: 30px; }

.page-shopping-cart .cart-worder {

padding: 20px; }

.page-shopping-cart .cart-worder .choose-worder {

color: #fff;

display: block;

background: #39e;

width: 140px;

height: 40px;

line-height: 40px;

border-radius: 4px;

text-align: center;

margin-right: 20px; }

.page-shopping-cart .cart-worder .choose-worder span {

display: inline-block;

vertical-align: top;

margin: 9px 10px 0 0;

width: 22px;

height: 22px;

background: url("shopping_cart.png") no-repeat -92px 0; }

.page-shopping-cart .cart-worder .worker-info {

color: #666; }

.page-shopping-cart .cart-worder .worker-info img {

border-radius: 100%;

margin-right: 10px; }

.page-shopping-cart .cart-worder .worker-info span {

color: #000; }

.choose-worker-box {

width: 620px;

background: #fff; }

.choose-worker-box .box-title {

height: 40px;

line-height: 40px;

background: #F7F7F7;

text-align: center;

position: relative;

font-size: 14px; }

.choose-worker-box .box-title a {

display: block;

position: absolute;

top: 15px;

right: 16px;

width: 10px;

height: 10px;

background: url("shopping_cart.png") no-repeat -80px 0; }

.choose-worker-box .box-title a:hover {

background: url("shopping_cart.png") no-repeat -80px -22px; }

.choose-worker-box .worker-list {

padding-top: 30px;

height: 134px;

overflow-y: auto; }

.choose-worker-box .worker-list li {

float: left;

width: 25%;

text-align: center;

margin-bottom: 30px; }

.choose-worker-box .worker-list li p {

margin-top: 8px; }

.choose-worker-box .worker-list li.cur a {

color: #f70; }

.choose-worker-box .worker-list li.cur a img {

border: 1px solid #f70; }

.choose-worker-box .worker-list li a:hover {

color: #f70; }

.choose-worker-box .worker-list li a:hover img {

border: 1px solid #f70; }

.choose-worker-box .worker-list li img {

border: 1px solid #fff;

border-radius: 100%; }

购物清单
全选
商品
数量
单价(元)
金额(元)
操作
【斯文】甘油 | 丙三醇

品牌:韩国skc  产地:韩国

规格/纯度:99.7%  起定量:215千克

配送仓储:上海仓海仓储

800.00

800.00

删除
【斯文】甘油 | 丙三醇

品牌:韩国skc  产地:韩国

规格/纯度:99.7%  起定量:215千克

配送仓储:上海仓海仓储

800.00

800.00

删除

删除所选商品

继续购物

去结算

¥1600

2件商品总计(不含运费):

new Vue({

el:'#shopping-cart',

data:{

},

computed: {},

methods:{

}

})

然后准备下列表数据,根据下面表格的箭头

所以大家就知道吗,下面的数据大概是涨这样

productList:[

{

'pro_name': '【斯文】甘油 | 丙三醇',//产品名称

'pro_brand': 'skc',//品牌名称

'pro_place': '韩国',//产地

'pro_purity': '99.7%',//规格

'pro_min': "215千克",//最小起订量

'pro_depot': '上海仓海仓储',//所在仓库

'pro_num': 3,//数量

'pro_img': '../../images/ucenter/testimg.jpg',//图片链接

'pro_price': 800//单价

}

]

准备了这么多,大家可能想到,还缺少一个,就是记录产品是否有选中,但是这个字段,虽然可以在上面那里加,但是意义不大,比如在平常项目那里!后台的数据不会这样返回,数据库也不会有这个字段,这个字段应该是自己添加的。代码如下

new Vue({

el:'#shopping-cart',

data:{

productList:[

{

'pro_name': '【斯文】甘油 | 丙三醇',//产品名称

'pro_brand': 'skc',//品牌名称

'pro_place': '韩国',//产地

'pro_purity': '99.7%',//规格

'pro_min': "215千克",//最小起订量

'pro_depot': '上海仓海仓储',//所在仓库

'pro_num': 3,//数量

'pro_img': '../../images/ucenter/testimg.jpg',//图片链接

'pro_price': 800//单价

}

]

},

computed: {},

methods:{

},

mounted:function () {

//为productList添加select(是否选中)字段,初始值为true

var _this=this;

//为productList添加select(是否选中)字段,初始值为true

this.productList.map(function (item) {

_this.$set(item, 'select', true);

})

//要像上面这样写双向绑定才能起效,下面的写法是有问题的,双向绑定不起效的!

//this.productList.map(function (item) {item.select=true})

}

})

步骤1

为了着重表示我修改了什么地方,代码我现在只贴出修改的部分,大家对着上面的布局,就很容易知道我改的是什么地方了!下面也是这样操作!

点击增加和减少按钮(箭头指向地方),所属列的金额改变(红框地方)

执行步骤1之前,要先把列表的数据给铺出来。利用v-for指令。代码如下

{{item.pro_name}}

品牌:{{item.pro_brand}}  产地:{{item.pro_place}}

规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}

配送仓储:{{item.pro_depot}}

{{item.pro_price.toFixed(2)}}

{{item.pro_price*item.pro_num}}.00

删除

这样,列表的数据就有了!

也可以发现,这两个按钮的功能已经实现了,后面的金额也会发生变化!是不是感到很惊喜!其实这里没什么特别的,就是因为输入框利用v-model绑定了数量(pro_num),然后两个按钮分别添加了事件@click="item.pro_num--"和@click="item.pro_num++"。比如刚开始pro_num是3,点击,pro_num就变成2,点击

,pro_num就变成4,然后后面的金额会改改,是因为{{item.pro_price*item.pro_num}}。只要pro_price或者pro_num的值改变了,整一块也会改变,视图就会刷新,我们就能看到变化(这些事情是vue做的,这就是MVVM的魅力,数据驱动视图改变)。

步骤2

点击所属列选择按钮(箭头指向地方),总计的金额(红框地方)和已选产品的列数(蓝框地方)和全选(黄框地方)会改变(如果已经全选了,全选按钮自动变成全选,如果没有全选,全选按钮,自动取消全选)!

首先,选择与取消选择,在这里只有两个操作(其实只有一个:改变这条记录的select字段)。

然后改变,如果这条记录select为false,就显示,否则就显示

代码如下

其实就是等于添加了@click="item.select=!item.select" :class="{'check-true':item.select}"这里。点击这个,这条数据的select字段就取反(true->false或者false->true)。然后:class="{'check-true':item.select}",就会根据这条数据的select字段进行判断,是否添加check-true类名,如果select字段为true,就添加类名,显示。否则不添加类名,显示

然后,全选按钮,是否变成。这里用一个computed(计算属性)就好。代码如下

html

全选

js

computed: {

isSelectAll:function(){

//如果productList中每一条数据的select都为true,返回true,否则返回false;

return this.productList.every(function (val) { return val.select});

}

}

代码我解释下,就是计算属性中,定义的isSelectAll依赖productList。只要productList改变,isSelectAll的返回值就会改变,然后:class="{'check-true':isSelectAll}"根绝isSelectAll返回值是否添加'check-true'类名,显示对应的样式!

最后,,这里的多少件产品和总价,也是使用计算属性,有了上一步的基础,给出代码,大家一看就明白了!

html

¥{{getTotal.totalPrice}}

{{getTotal.totalNum}}件商品总计(不含运费):

js

computed: {

//检测是否全选

isSelectAll:function(){

//如果productList中每一条数据的select都为true,返回true,否则返回false;

return this.productList.every(function (val) { return val.select});

},

//获取总价和产品总件数

getTotal:function(){

//获取productList中select为true的数据。

var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0;

for(var i=0,len=_proList.length;i

//总价累加

totalPrice+=_proList[i].pro_num*_proList[i].pro_price;

}

//选择产品的件数就是_proList.length,总价就是totalPrice

return {totalNum:_proList.length,totalPrice:totalPrice}

}

},

代码很简单,html根据getTotal返回值显示数据,getTotal依赖productList的数据,只要productList改变,返回值会改变,视图也会改变!

步骤3

点击全选按钮(箭头指向部分),会自动的对产品进行全选或者取消全选,下面的总计也会发生改变

做到这一步,大家应该知道,全选或者取消全选,就是改变记录的select。但是怎么知道现在的列表有没有全选呢?这个很贱,不需要在操作函数(全选与取消全选函数)里面遍历,大家应该还记得第二步的计算属性isSelectAll(为true就是全选,否则不是全选),把这个传进操作函数就好,然后操作函数,根据参数,决定执行全选,还是取消全选操作。代码如下!

html

全选

js

methods: {

//全选与取消全选

selectProduct:function(_isSelect){

//遍历productList,全部取反

for (var i = 0, len = this.productList.length; i < len; i++) {

this.productList[i].select = !_isSelect;

}

}

},

步骤4

点击删除产品,会删除已经选中的,全选按钮和下面的总计,都会变化!点击每条记录后面的删除,会删除当前的这条记录。全选按钮和下面的总计,也都会变化!

首先,点击删除产品,删除已经选中。这个大家知道了怎么做了!就是遍历productList,如果哪条记录的select为true,就删除。

然后,点击每条记录后面的删除,删除当前的这条记录。这个在html遍历productList的时候。顺便带上索引,然后把索引当成参数,传进操作函数,然后根据索引参数,删除productList的哪一条记录。即可实现!代码如下!

html

{{item.pro_name}}

品牌:{{item.pro_brand}}  产地:{{item.pro_place}}

规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}

配送仓储:{{item.pro_depot}}

{{item.pro_price.toFixed(2)}}

{{item.pro_price*item.pro_num}}.00

删除

...

删除所选商品

js

//删除已经选中(select=true)的产品

deleteProduct:function () {

this.productList=this.productList.filter(function (item) {return !item.select})

},

//删除单条产品

deleteOneProduct:function (index) {

//根据索引删除productList的记录

this.productList.splice(index,1);

},

完整代码

样式图片

Title

.fl {

float: left;

}

.fr {

float: right;

}

blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul {

margin: 0;

padding: 0;

}

.clearfix {

zoom: 1;

}

.clearfix:after {

clear: both;

}

.clearfix:after {

content: '.';

display: block;

overflow: hidden;

visibility: hidden;

font-size: 0;

line-height: 0;

width: 0;

height: 0;

}

a {

text-decoration: none;

color: #333;

}

img {

vertical-align: middle;

}

.page-shopping-cart {

width: 1200px;

margin: 50px auto;

font-size: 14px;

border: 1px solid #e3e3e3;

border-top: 2px solid #317ee7;

}

.page-shopping-cart .cart-title {

color: #317ee7;

font-size: 16px;

text-align: left;

padding-left: 20px;

line-height: 68px;

}

.page-shopping-cart .red-text {

color: #e94826;

}

.page-shopping-cart .check-span {

display: block;

width: 24px;

height: 20px;

background: url("shopping_cart.png") no-repeat 0 0;

}

.page-shopping-cart .check-span.check-true {

background: url("shopping_cart.png") no-repeat 0 -22px;

}

.page-shopping-cart .td-check {

width: 70px;

}

.page-shopping-cart .td-product {

width: 460px;

}

.page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total {

width: 160px;

}

.page-shopping-cart .td-do {

width: 150px;

}

.page-shopping-cart .cart-product-title {

text-align: center;

height: 38px;

line-height: 38px;

padding: 0 20px;

background: #f7f7f7;

border-top: 1px solid #e3e3e3;

border-bottom: 1px solid #e3e3e3;

}

.page-shopping-cart .cart-product-title .td-product {

text-align: center;

font-size: 14px;

}

.page-shopping-cart .cart-product-title .td-check {

text-align: left;

}

.page-shopping-cart .cart-product-title .td-check .check-span {

margin: 9px 6px 0 0;

}

.page-shopping-cart .cart-product {

padding: 0 20px;

text-align: center;

}

.page-shopping-cart .cart-product table {

width: 100%;

text-align: center;

font-size: 14px;

}

.page-shopping-cart .cart-product table td {

padding: 20px 0;

}

.page-shopping-cart .cart-product table tr {

border-bottom: 1px dashed #e3e3e3;

}

.page-shopping-cart .cart-product table tr:last-child {

border-bottom: none;

}

.page-shopping-cart .cart-product table .product-num {

border: 1px solid #e3e3e3;

display: inline-block;

text-align: center;

}

.page-shopping-cart .cart-product table .product-num .num-do {

width: 24px;

height: 28px;

display: block;

background: #f7f7f7;

}

.page-shopping-cart .cart-product table .product-num .num-reduce span {

background: url("shopping_cart.png") no-repeat -40px -22px;

display: block;

width: 6px;

height: 2px;

margin: 13px auto 0 auto;

}

.page-shopping-cart .cart-product table .product-num .num-add span {

background: url("shopping_cart.png") no-repeat -60px -22px;

display: block;

width: 8px;

height: 8px;

margin: 10px auto 0 auto;

}

.page-shopping-cart .cart-product table .product-num .num-input {

width: 42px;

height: 28px;

line-height: 28px;

border: none;

text-align: center;

}

.page-shopping-cart .cart-product table .td-product {

text-align: left;

font-size: 12px;

line-height: 20px;

}

.page-shopping-cart .cart-product table .td-product img {

border: 1px solid #e3e3e3;

margin-right: 10px;

}

.page-shopping-cart .cart-product table .td-product .product-info {

display: inline-block;

vertical-align: middle;

}

.page-shopping-cart .cart-product table .td-do {

font-size: 12px;

}

.page-shopping-cart .cart-product-info {

height: 50px;

line-height: 50px;

background: #f7f7f7;

padding-left: 20px;

}

.page-shopping-cart .cart-product-info .delect-product {

color: #666;

}

.page-shopping-cart .cart-product-info .delect-product span {

display: inline-block;

vertical-align: top;

margin: 18px 8px 0 0;

width: 13px;

height: 15px;

background: url("shopping_cart.png") no-repeat -60px 0;

}

.page-shopping-cart .cart-product-info .product-total {

font-size: 14px;

color: #e94826;

}

.page-shopping-cart .cart-product-info .product-total span {

font-size: 20px;

}

.page-shopping-cart .cart-product-info .check-num {

color: #333;

}

.page-shopping-cart .cart-product-info .check-num span {

color: #e94826;

}

.page-shopping-cart .cart-product-info .keep-shopping {

color: #666;

margin-left: 40px;

}

.page-shopping-cart .cart-product-info .keep-shopping span {

display: inline-block;

vertical-align: top;

margin: 18px 8px 0 0;

width: 15px;

height: 15px;

background: url("shopping_cart.png") no-repeat -40px 0;

}

.page-shopping-cart .cart-product-info .btn-buy {

height: 50px;

color: #fff;

font-size: 20px;

display: block;

width: 110px;

background: #ff7700;

text-align: center;

margin-left: 30px;

}

.page-shopping-cart .cart-worder {

padding: 20px;

}

.page-shopping-cart .cart-worder .choose-worder {

color: #fff;

display: block;

background: #39e;

width: 140px;

height: 40px;

line-height: 40px;

border-radius: 4px;

text-align: center;

margin-right: 20px;

}

.page-shopping-cart .cart-worder .choose-worder span {

display: inline-block;

vertical-align: top;

margin: 9px 10px 0 0;

width: 22px;

height: 22px;

background: url("shopping_cart.png") no-repeat -92px 0;

}

.page-shopping-cart .cart-worder .worker-info {

color: #666;

}

.page-shopping-cart .cart-worder .worker-info img {

border-radius: 100%;

margin-right: 10px;

}

.page-shopping-cart .cart-worder .worker-info span {

color: #000;

}

.choose-worker-box {

width: 620px;

background: #fff;

}

.choose-worker-box .box-title {

height: 40px;

line-height: 40px;

background: #F7F7F7;

text-align: center;

position: relative;

font-size: 14px;

}

.choose-worker-box .box-title a {

display: block;

position: absolute;

top: 15px;

right: 16px;

width: 10px;

height: 10px;

background: url("shopping_cart.png") no-repeat -80px 0;

}

.choose-worker-box .box-title a:hover {

background: url("shopping_cart.png") no-repeat -80px -22px;

}

.choose-worker-box .worker-list {

padding-top: 30px;

height: 134px;

overflow-y: auto;

}

.choose-worker-box .worker-list li {

float: left;

width: 25%;

text-align: center;

margin-bottom: 30px;

}

.choose-worker-box .worker-list li p {

margin-top: 8px;

}

.choose-worker-box .worker-list li.cur a {

color: #f70;

}

.choose-worker-box .worker-list li.cur a img {

border: 1px solid #f70;

}

.choose-worker-box .worker-list li a:hover {

color: #f70;

}

.choose-worker-box .worker-list li a:hover img {

border: 1px solid #f70;

}

.choose-worker-box .worker-list li img {

border: 1px solid #fff;

border-radius: 100%;

}

购物清单
全选
商品
数量
单价(元)
金额(元)
操作
{{item.pro_name}}

品牌:{{item.pro_brand}}  产地:{{item.pro_place}}

规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}

配送仓储:{{item.pro_depot}}

{{item.pro_price.toFixed(2)}}

{{item.pro_price*item.pro_num}}.00

删除

删除所选商品

继续购物

去结算

¥{{getTotal.totalPrice}}

{{getTotal.totalNum}}件商品总计(不含运费):

new Vue({

el: '#shopping-cart',

data: {

productList: [

{

'pro_name': '【斯文】甘油 | 丙三醇',//产品名称

'pro_brand': 'skc',//品牌名称

'pro_place': '韩国',//产地

'pro_purity': '99.7%',//规格

'pro_min': "215千克",//最小起订量

'pro_depot': '上海仓海仓储',//所在仓库

'pro_num': 3,//数量

'pro_img': '../../images/ucenter/testimg.jpg',//图片链接

'pro_price': 800//单价

},

{

'pro_name': '【斯文】甘油 | 丙三醇',//产品名称

'pro_brand': 'skc',//品牌名称

'pro_place': '韩国',//产地

'pro_purity': '99.7%',//规格

'pro_min': "215千克",//最小起订量

'pro_depot': '上海仓海仓储',//所在仓库

'pro_num': 3,//数量

'pro_img': '../../images/ucenter/testimg.jpg',//图片链接

'pro_price': 800//单价

},

{

'pro_name': '【斯文】甘油 | 丙三醇',//产品名称

'pro_brand': 'skc',//品牌名称

'pro_place': '韩国',//产地

'pro_purity': '99.7%',//规格

'pro_min': "215千克",//最小起订量

'pro_depot': '上海仓海仓储',//所在仓库

'pro_num': 3,//数量

'pro_img': '../../images/ucenter/testimg.jpg',//图片链接

'pro_price': 800//单价

}

]

},

computed: {

//检测是否全选

isSelectAll:function(){

//如果productList中每一条数据的select都为true,返回true,否则返回false;

return this.productList.every(function (val) { return val.select});

},

//获取总价和产品总件数

getTotal:function(){

//获取productList中select为true的数据。

var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0;

for(var i=0,len=_proList.length;i

//总价累加

totalPrice+=_proList[i].pro_num*_proList[i].pro_price;

}

//选择产品的件数就是_proList.length,总价就是totalPrice

return {totalNum:_proList.length,totalPrice:totalPrice}

}

},

methods: {

//全选与取消全选

selectProduct:function(_isSelect){

//遍历productList,全部取反

for (var i = 0, len = this.productList.length; i < len; i++) {

this.productList[i].select = !_isSelect;

}

},

//删除已经选中(select=true)的产品

deleteProduct:function () {

this.productList=this.productList.filter(function (item) {return !item.select})

},

//删除单条产品

deleteOneProduct:function (index) {

//根据索引删除productList的记录

this.productList.splice(index,1);

},

},

mounted: function () {

var _this=this;

//为productList添加select(是否选中)字段,初始值为true

this.productList.map(function (item) {

_this.$set(item, 'select', true);

})

}

})

5.todoList

运行效果

原理分析和实现

首先,还是先把布局写好,和引入vue,准备vue实例,这个不多说,代码如下

body{font-family: "微软雅黑";font-size: 14px;}

input{font-size: 14px;}

body,ul,div,html{padding: 0;margin: 0;}

.hidden{display: none;}

.main{width: 800px;margin: 0 auto;}

li{list-style-type: none;line-height: 40px;position: relative;border: 1px solid transparent;padding: 0 20px;}

li .type-span{display: block;width: 10px;height: 10px;background: #ccc;margin: 14px 10px 0 0 ;float: left;}

li .close{position: absolute;color: #f00;font-size: 20px;line-height: 40px;height: 40px;right: 20px;cursor: pointer;display: none;top: 0;}

li:hover{border: 1px solid #09f;}

li:hover .close{display: block;}

li .text-keyword{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;}

.text-keyword{box-sizing: border-box;width: 100%;height: 40px;padding-left: 10px;outline: none;}

小目标列表

添加小目标

共有N个目标

所有目标

已完成目标

未完成目标

  • html5

    X

  • css3

    X

new Vue({

el: "#app",

data: {

},

computed:{

},

methods:{

}

});

布局有了,相当于一个骨架就有了,下面实现功能,一个一个来

步骤1

输入并回车,多一条记录。下面的记录文字也会改变

首先,大的输入框回车要添加纪录,那么输入框必须绑定一个值和一个添加纪录的方法。

代码如下:

然后,下面的记录也要改变,所以,下面的记录也要帮一个值,因为这个记录可能会有多个,这个值就是一个数组,也可以看到,记录除了名称,还有记录是否完成的状态,所以,绑定记录的这个值肯定是一个对象数组!代码如下

最后,记录文字要改变。这个只是一个当前记录的长度即可!

为了着重表示我修改了什么地方,代码我现在只贴出修改的部分,大家对着上面的布局,就很容易知道我改的是什么地方了!下面也是这样操作!

html代码

共有{{prolist.length}}个目标

{{list.name}}

X

js代码

new Vue({

el: "#app",

data: {

addText:'',

//name-名称,status-完成状态

prolist:[

{name:"HTML5",status:false},

{name:"CSS3",status:false},

{name:"vue",status:false},

{name:"react",status:false}

]

},

computed:{

},

methods:{

addList(){

//添加进来默认status=false,就是未完成状态

this.prolist.push({

name:this.addText,

status:false

});

//添加后,清空addText

this.addText="";

}

}

});

测试一下,没问题

步骤2

点击切换,下面记录会改变

看到三个选项,也很简单,无非就是三个选择,一个是所有的目标,一个是所有已经完成的目标,一个是所有没完成的目标。

首先.新建一个新的变量(newList),储存prolist。遍历的时候不再遍历prolist,而是遍历newList。改变也是改变newList。

然后.选择所有目标的时候,显示全部prolist,把prolist赋值给newList。

然后.选择所有已经完成目标的时候,只显示prolist中,status为true的目标,把prolist中,status为true的项赋值给newList,

最后.选择所有未完成目标的时候,只显示status为false的目标,把prolist中,status为false的项赋值给newList。

代码如下

html

  • {{list.name}}

    X

js

new Vue({

el: "#app",

data: {

addText:'',

//name-名称,status-完成状态

prolist:[

{name:"HTML5",status:false},

{name:"CSS3",status:false},

{name:"vue",status:false},

{name:"react",status:false}

],

newList:[]

},

computed:{

noend:function(){

return this.prolist.filter(function(item){

return !item.status

}).length;

}

},

methods:{

addList(){

//添加进来默认status=false,就是未完成状态

this.prolist.push({

name:this.addText,

status:false

});

//添加后,清空addText

this.addText="";

},

chooseList(type){

//type=1时,选择所有目标

//type=2时,选择所有已完成目标

//type=3时,选择所有未完成目标

switch(type){

case 1:this.newList=this.prolist;break;

case 2:this.newList=this.prolist.filter(function(item){return item.status});break;

case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;

}

},

delectList(index){

//根据索引,删除数组某一项

this.prolist.splice(index,1);

//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList

this.newList=this.prolist;

},

},

mounted(){

//初始化,把prolist赋值给newList。默认显示所有目标

this.newList=this.prolist;

}

});

运行结果

步骤3

红色关闭标识,点击会删除该记录。前面按钮点击会切换该记录完成状态,颜色也改变,记录文字也跟着改变

首先点击红色关闭标识,点击会删除该记录。这个应该没什么问题,就是删除prolist的一条记录!

然后前面按钮点击会切换该记录完成状态。这个也没什么,就是改变prolist的一条记录的status字段!

最后记录文字的改变,就是记录prolist中status为false的有多少条,prolist中status为true的有多少条而已

html代码

共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}

  • {{list.name}}

    X

js

new Vue({

el: "#app",

data: {

addText:'',

//name-名称,status-完成状态

prolist:[

{name:"HTML5",status:false},

{name:"CSS3",status:false},

{name:"vue",status:false},

{name:"react",status:false}

],

newList:[]

},

computed:{

//计算属性,返回未完成目标的条数,就是数组里面status=false的条数

noend:function(){

return this.prolist.filter(function(item){

return !item.status

}).length;

}

},

methods:{

addList(){

//添加进来默认status=false,就是未完成状态

this.prolist.push({

name:this.addText,

status:false

});

//添加后,清空addText

this.addText="";

},

chooseList(type){

switch(type){

case 1:this.newList=this.prolist;break;

case 2:this.newList=this.prolist.filter(function(item){return item.status});break;

case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;

}

},

delectList(index){

//根据索引,删除数组某一项

this.prolist.splice(index,1);

//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList

this.newList=this.prolist;

},

},

mounted(){

this.newList=this.prolist;

}

});

运行结果

步骤4

文字双击会出现输入框,可输入文字,如果回车或者失去焦点,就改变文字,如果按下ESC就恢复原来的文字

首先.双击出现输入框,就是双击文字后,给当前的li设置一个类名(‘eidting’),然后写好样式。当li出现这个类名的时候,就出现输入框,并且隐藏其它内容。

然后.回车或者失去焦点,就改变文字这个只需要操作一个,就是把类名(‘eidting’)清除掉。然后输入框就会隐藏,其它内容显示!

最后.按下ESC就恢复原来的文字,就是出现输入框的时候,用一个变量(‘beforeEditText’)先保存当前的内容,然后按下了ESC,就把变量(‘beforeEditText’)赋值给当前操作的值!

代码如下:

html

  • {{list.name}}

    X

css(加上)

li div{display: block;}

li.eidting div{display: none;}

li .text2{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;}

li.eidting .text2{display: block;}

js

methods:{

addList(){

//添加进来默认status=false,就是未完成状态

this.prolist.push({

name:this.addText,

status:false

});

//添加后,清空addText

this.addText="";

},

chooseList(type){

//type=1时,选择所有目标

//type=2时,选择所有已完成目标

//type=3时,选择所有未完成目标

switch(type){

case 1:this.newList=this.prolist;break;

case 2:this.newList=this.prolist.filter(function(item){return item.status});break;

case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;

}

},

delectList(index){

//根据索引,删除数组某一项

this.prolist.splice(index,1);

//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList

this.newList=this.prolist;

},

//修改前

editBefore(name){

//先记录当前项(比如这一项,{name:"HTML5",status:false})

//beforeEditText="HTML5"

this.beforeEditText=name;

},

//修改完成后

edited(){

//修改完了,设置curIndex="",这样输入框就隐藏,其它元素就会显示。因为在li元素 写了::class="{'eidting':curIndex===index}" 当curIndex不等于index时,eidting类名就清除了!

//输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步只是清除eidting类名,隐藏输入框而已

//还有一个要注意的就是虽然li遍历的是newList,比如改了newList的这一项({name:"HTML5",status:false}),比如改成这样({name:"HTML",status:true})。实际上prolist的这一项({name:"HTML5",status:false}),也会被改成({name:"HTML",status:true})。因为这里是一个对象,而且公用一个堆栈!修改其中一个,另一个会被影响到

this.curIndex="";

},

//取消修改

cancelEdit(val){

//上面说了输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步就是把之前保存的beforeEditText赋值给当前项的name属性,起到一个恢复原来值得作用!

val.name=this.beforeEditText;

this.curIndex="";

}

},

运行结果

还有一个小细节,大家可能注意到了,就是双击文字,出来输入框的时候,还要自己手动点击一下,才能获得焦点,我们想双击了,输入框出来的时候,自动获取焦点,怎么办?自定义指令就行了!

computed:{...},

methods:{...},

mounted(){...},

directives:{

"focus":{

update(el){

el.focus();

}

}

}

然后html 调用指令

完整代码

body{font-family: "微软雅黑";font-size: 14px;}

input{font-size: 14px;}

body,ul,div,html{padding: 0;margin: 0;}

.hidden{display: none;}

.main{width: 800px;margin: 0 auto;}

li{list-style-type: none;line-height: 40px;position: relative;border: 1px solid transparent;padding: 0 20px;}

li .status-span{display: block;width: 10px;height: 10px;background: #ccc;margin: 14px 10px 0 0 ;float: left;}

li .status-span.status-end{

background: #09f;

}

li .close{position: absolute;color: #f00;font-size: 20px;line-height: 40px;height: 40px;right: 20px;cursor: pointer;display: none;top: 0;}

li:hover{border: 1px solid #09f;}

li:hover .close{display: block;}

li div{display: block;}

li.eidting div{display: none;}

li .text2{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;}

li.eidting .text2{display: block;}

li .text-keyword{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;}

.text-keyword{box-sizing: border-box;width: 100%;height: 40px;padding-left: 10px;outline: none;}

小目标列表

添加小目标

共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}

所有目标

已完成目标

未完成目标

  • {{list.name}}

    X

new Vue({

el: "#app",

data: {

addText:'',

//name-名称,status-完成状态

prolist:[

{name:"HTML5",status:false},

{name:"CSS3",status:false},

{name:"vue",status:false},

{name:"react",status:false}

],

newList:[],

curIndex:'',

beforeEditText:"",

curType:0

},

computed:{

//计算属性,返回未完成目标的条数,就是数组里面status=false的条数

noend:function(){

return this.prolist.filter(function(item){

return !item.status

}).length;

}

},

methods:{

addList(){

//添加进来默认status=false,就是未完成状态

this.prolist.push({

name:this.addText,

status:false

});

//添加后,清空addText

this.addText="";

},

chooseList(type){

//type=1时,选择所有目标

//type=2时,选择所有已完成目标

//type=3时,选择所有未完成目标

this.curType=type;

switch(type){

case 1:this.newList=this.prolist;break;

case 2:this.newList=this.prolist.filter(function(item){return item.status});break;

case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;

}

},

/*改变单条数据的完成状态*/

changeType(index){

this.newList[index].status=!this.newList[index].status;

//更新数据

this.chooseList(this.curType);

},

delectList(list){

var index=this.prolist.indexOf(list);

//根据索引,删除数组某一项

this.prolist.splice(index,1);

//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList

//this.newList=this.prolist;

this.chooseList(this.curType);

},

//修改前

editBefore(name){

//先记录当前项(比如这一项,{name:"HTML5",status:false})

//beforeEditText="HTML5"

this.beforeEditText=name;

},

//修改完成后

edited(){

//修改完了,设置curIndex="",这样输入框就隐藏,其它元素就会显示。因为在li元素 写了::class="{'eidting':curIndex===index}" 当curIndex不等于index时,eidting类名就清除了!

//输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步只是清除eidting类名,隐藏输入框而已

//还有一个要注意的就是虽然li遍历的是newList,比如改了newList的这一项({name:"HTML5",status:false}),比如改成这样({name:"HTML",status:true})。实际上prolist的这一项({name:"HTML5",status:false}),也会被改成({name:"HTML",status:true})。因为这里是一个对象,而且公用一个堆栈!修改其中一个,另一个会被影响到

this.curIndex="";

},

//取消修改

cancelEdit(val){

//上面说了输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步就是把之前保存的beforeEditText赋值给当前项的name属性,起到一个恢复原来值得作用!

val.name=this.beforeEditText;

this.curIndex="";

}

},

mounted(){

//初始化,把prolist赋值给newList。默认显示所有目标

this.newList=this.prolist;

},

directives:{

"focus":{

update(el){

el.focus();

}

}

}

});

6.小结

好了,三个小实例在这里就说完了!别看文章这么长,其实都是基础,可能是我比较啰嗦而已!如果大家能熟透这几个小实例,相信用vue做项目也是信手拈来。基础的语法在这里了,有了基础,高级的写法也不会很难学习!如果以后,我有什么要分享的,我会继续分享。最后一句老话,如果觉得我哪里写错了,写得不好,欢迎指点!

-------------------------华丽的分割线--------------------

想了解更多,关注关注我的微信公众号:守候书阁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值