1. Введение
Я работаю над проектами с vue некоторое время. Но я не написал статью об основах ввода Vue, поэтому сегодня я напишу три небольших примера ввода Vue. Эти три небольших примера — мои практические работы, когда я впервые столкнулся с Vue. Сложность варьируется от очень простой к простому.это начальный уровень. Я надеюсь, что это поможет вам лучше изучить и понять vue, а также позволит вам просмотреть vue. Если вы нашли что-то не так в статье, напишите это неправильно или у вас есть предложения! Добро пожаловать, чтобы дать указатели на лабиринт!
1. Версия vue, используемая в этой статье,
2.4.2
, может отличаться от новой версии, всем следует обратить внимание.
2. Теперь я также предполагаю, что у вас есть базовые знания html, css и javascript, и вы уже прочитали этоОфициальный сайтБазовое введение в Vue, общее представление о vue, понимание часто используемых инструкций vue (v-model, v-show, v-if, v-for, v-on, v-bind и т. д.)! Если вы новичок во фронтенде, вы можете растеряться при прочтении статьи, рекомендуется сначала изучить основы, а уже потом читать после того, как вы освоите базовые знания!
3. В следующем примере рекомендуется делать это во время чтения статьи! Таким образом, мышление будет очень ясным и его не так просто запутать! Я не думаю, что статья длинная (статья длинная, чтобы все могли увидеть больше информации, и размещено много повторяющихся кодов. Эти коды. html, css и т. д. можно полностью пропустить). Если вы только прочитали статью, возможно, вы не сможете ее прочитать, потому что статья, о которой я говорил, относительно подробная и относительно длинная!
4. Эти примеры взяты из моего собственного проекта ежедневной практики, и код был упомянут на github (vue-demos). Добро пожаловать в звезду. !
2. Что такое вью
Vue — это очень популярный интерфейсный MVVM-фреймворк, построенный с идеей управления данными и компонентизации, который называется тремя фронтенд-фреймворками вместе с angular и react. По сравнению с angular и react, vue более легкий, высокопроизводительный и простой в использовании. Вы также можете перейти и взглянуть на введение и основные функции vue.Введение на официальном сайте. Простое и грубое понимание таково: при разработке с vue нужно манипулировать данными, а затем vue обработает их и изменит DOM с помощью data-driven (я не знаю, правильно ли я понимаю, и дайте мне несколько указателей, если неправильно понимаю).
Вот простое объяснение примеров
код показывает, как показано ниже
html
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
js
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
Я думаю, это нетрудно понять, т.input
границаmessage
это значение, то вinput
При изменении,message
Просто изменился, за счет двусторонней привязки, заодно и html страницы ({{ message }}
) был изменен!
Что ж, пойдем на пример учиться!
3. Вкладки
текущий результат
Принцип анализа и реализации
Это очень просто, не более чем щелчок для переключения дисплея. Но это должен сделать каждый. Если это понятно, посмотрите на следующие два! Этот экземпляр должен быть просто разминкой и знакомым эффектом!
Этот шаг — всего лишь один шаг, а принцип — ничто. Я прокомментировал прямо код, и после прочтения комментариев все поняли!
полный код
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
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;
}
</style>
<body>
<div id="tab">
<div class="tab-tit">
<!--点击设置curId的值 如果curId等于0,第一个a添加cur类名,如果curId等于1,第二个a添加cur类名,以此类推。添加了cur类名,a就会改变样式 @click,:class ,v-show这三个是vue常用的指令或添加事件的方式-->
<a href="javascript:;" @click="curId=0" :class="{'cur':curId===0}">html</a>
<a href="javascript:;" @click="curId=1" :class="{'cur':curId===1}">css</a>
<a href="javascript:;" @click="curId=2" :class="{'cur':curId===2}">javascript</a>
<a href="javascript:;" @click="curId=3" :class="{'cur':curId===3}">vue</a>
</div>
<div class="tab-con">
<!--根据curId的值显示div,如果curId等于0,第一个div显示,其它三个div不显示。如果curId等于1,第二个div显示,其它三个div不显示。以此类推-->
<div v-show="curId===0">
html<br/>
</div>
<div v-show="curId===1">
css
</div>
<div v-show="curId===2">
javascript
</div>
<div v-show="curId===3">
vue
</div>
</div>
</div>
</body>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#tab',
data: {
curId: 0
},
computed: {},
methods: {},
mounted: function () {
}
})
</script>
</html>
4. Статистическая общая цена
текущий результат
Принцип анализа и реализации
Прежде всего, лучше сначала написать макет, и ввести vue, и подготовить экземпляр vue.Это не так много, код выглядит следующим образом
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.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%; }
</style>
</head>
<body>
<div class="page-shopping-cart" id="shopping-cart">
<h4 class="cart-title">购物清单</h4>
<div class="cart-product-title clearfix">
<div class="td-check fl"><span class="check-span fl check-all"></span>全选</div>
<div class="td-product fl">商品</div>
<div class="td-num fl">数量</div>
<div class="td-price fl">单价(元)</div>
<div class="td-total fl">金额(元)</div>
<div class="td-do fl">操作</div>
</div>
<div class="cart-product clearfix">
<table>
<tbody><tr>
<td class="td-check"><span class="check-span"></span></td>
<td class="td-product"><img src="testimg.jpg" width="98" height="98">
<div class="product-info">
<h6>【斯文】甘油 | 丙三醇</h6>
<p>品牌:韩国skc 产地:韩国</p>
<p>规格/纯度:99.7% 起定量:215千克</p>
<p>配送仓储:上海仓海仓储</p>
</div>
<div class="clearfix"></div>
</td>
<td class="td-num">
<div class="product-num">
<a href="javascript:;" class="num-reduce num-do fl"><span></span></a>
<input type="text" class="num-input" value="3">
<a href="javascript:;" class="num-add num-do fr"><span></span></a>
</div>
</td>
<td class="td-price">
<p class="red-text">¥<span class="price-text">800</span>.00</p>
</td>
<td class="td-total">
<p class="red-text">¥<span class="total-text">800</span>.00</p>
</td>
<td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>
</tr>
<tr>
<td class="td-check"><span class="check-span check-true"></span></td>
<td class="td-product"><img src="testimg.jpg" width="98" height="98">
<div class="product-info">
<h6>【斯文】甘油 | 丙三醇</h6>
<p>品牌:韩国skc 产地:韩国</p>
<p>规格/纯度:99.7% 起定量:215千克</p>
<p>配送仓储:上海仓海仓储</p>
</div>
<div class="clearfix"></div>
</td>
<td class="td-num">
<div class="product-num">
<a href="javascript:;" class="num-reduce num-do fl"><span></span></a>
<input type="text" class="num-input" value="1">
<a href="javascript:;" class="num-add num-do fr"><span></span></a>
</div>
</td>
<td class="td-price">
<p class="red-text">¥<span class="price-text">800</span>.00</p>
</td>
<td class="td-total">
<p class="red-text">¥<span class="total-text">800</span>.00</p>
</td>
<td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>
</tr>
</tbody></table>
</div>
<div class="cart-product-info">
<a class="delect-product" href="javascript:;"><span></span>删除所选商品</a>
<a class="keep-shopping" href="#"><span></span>继续购物</a>
<a class="btn-buy fr" href="javascript:;">去结算</a>
<p class="fr product-total">¥<span>1600</span></p>
<p class="fr check-num"><span>2</span>件商品总计(不含运费):</p>
</div>
<div class="cart-worder clearfix">
<a href="javascript:;" class="choose-worder fl"><span></span>绑定跟单员</a>
<div class="worker-info fl">
</div>
</div>
</div>
</body>
<script src="vue.min.js"></script>
<script>
new Vue({
el:'#shopping-cart',
data:{
},
computed: {},
methods:{
}
})
</script>
</html>
Затем подготовьте следующие табличные данные в соответствии со стрелками в таблице ниже.
Итак, знаете ли вы, что следующие данные, вероятно, растут вот так?
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. код показывает, как показано ниже
<tr v-for="item in productList">
<td class="td-check"><span class="check-span"></span></td>
<td class="td-product"><img :src="item.pro_img" width="98" height="98">
<div class="product-info">
<h6>{{item.pro_name}}</h6>
<p>品牌:{{item.pro_brand}} 产地:{{item.pro_place}}</p>
<p>规格/纯度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p>
<p>配送仓储:{{item.pro_depot}}</p>
</div>
<div class="clearfix"></div>
</td>
<td class="td-num">
<div class="product-num">
<a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a>
<input type="text" class="num-input" v-model="item.pro_num">
<a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>
</div>
</td>
<td class="td-price">
<p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>
</td>
<td class="td-total">
<p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>
</td>
<td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>
</tr>
Таким образом, данные списка есть!
также можно найти,Функции этих двух кнопок реализованы, а количество сзади тоже изменится! Вы удивлены! На самом деле здесь нет ничего особенного, потому что поле ввода использует v-модель для привязки количества (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
, это показывает, в противном случае отображается.
код показывает, как показано ниже
<td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td>
По сути, это эквивалентно добавлению@click="item.select=!item.select" :class="{'check-true':item.select}"
здесь. Щелкните это, эти данныеselect
Поле инвертировано (true->false или false->true). потом:class="{'check-true':item.select}"
, Он будет основан на этих данныхselect
поле, чтобы решить, следует ли добавитьcheck-true
имя класса, еслиselect
Если поле истинно, добавьте имя класса и отобразите. В противном случае не добавляйте имя класса, отображайте
.
Потом,Кнопка «Выбрать все», становится ли она. Просто используйте вычисляемое (вычисляемое свойство) здесь. код показывает, как показано ниже
html
<div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}"></span>全选</div>
js
computed: {
isSelectAll:function(){
//如果productList长度为0
if(this.productList.length===0){
return false;
}
//如果productList中每一条数据的select都为true,返回true,否则返回false;
return this.productList.every(function (val) { return val.select});
}
}
Позвольте мне объяснить код, то есть в вычисляемом свойстве isSelectAll определенная зависимость от productList. Возвращаемое значение isSelectAll изменяется всякий раз, когда изменяется productList, затем:class="{'check-true':isSelectAll}"
Добавлять ли возвращаемое значение isSelectAll'check-true'
Имя класса, отобразите соответствующий стиль!
наконец,, количество продуктов и общая цена здесь также являются вычисляемыми атрибутами.С основанием предыдущего шага, учитывая код, все поймут с первого взгляда!
html
<p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p>
<p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品总计(不含运费):</p>
js
computed: {
//检测是否全选
isSelectAll:function(){
//如果productList长度为0
if(this.productList.length===0){
return false;
}
//如果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<len;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
(Если это правда, это означает выбрать все, иначе не выбрать все), просто передайте это в функцию операции, а затем используйте функцию, чтобы решить, выполнять ли операцию выбора всех или отменить операцию выбора всех в соответствии с параметры. код показывает, как показано ниже!
html
<div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}"@click="selectProduct(isSelectAll)"></span>全选</div>
js
methods: {
//全选与取消全选
selectProduct:function(_isSelect){
//遍历productList,全部取反
for (var i = 0, len = this.productList.length; i < len; i++) {
this.productList[i].select = !_isSelect;
}
}
},
Шаг 4
Нажмите, чтобы удалить продукт, он удалит выбранный продукт, кнопка «Выбрать все» и общее количество ниже изменится! Щелкните Удалить после каждой записи, чтобы удалить текущую запись. Кнопка «Выбрать все» и сумма внизу также изменятся!
Сначала нажмите Удалить продукт, чтобы удалить уже выбранный. Все знают, как это сделать! Это нужно пройти по productList, и если выбор какой записи верен, удалить его.
Затем щелкните Удалить после каждой записи, чтобы удалить текущую запись. Это когда html проходит через productList. Кстати, возьмите индекс, а затем используйте индекс в качестве параметра, передайте его в функцию операции, а затем удалите какую запись productList в соответствии с параметром индекса. Вот и все! код показывает, как показано ниже!
html
<!--遍历的时候带上索引-->
<tr v-for="(item,index) in productList">
<td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td>
<td class="td-product"><img :src="item.pro_img" width="98" height="98">
<div class="product-info">
<h6>{{item.pro_name}}</h6>
<p>品牌:{{item.pro_brand}} 产地:{{item.pro_place}}</p>
<p>规格/纯度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p>
<p>配送仓储:{{item.pro_depot}}</p>
</div>
<div class="clearfix"></div>
</td>
<td class="td-num">
<div class="product-num">
<a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a>
<input type="text" class="num-input" v-model="item.pro_num">
<a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>
</div>
</td>
<td class="td-price">
<p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>
</td>
<td class="td-total">
<p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>
</td>
<td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">删除</a></td>
</tr>
...
<a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>删除所选商品</a>
js
//删除已经选中(select=true)的产品
deleteProduct:function () {
this.productList=this.productList.filter(function (item) {return !item.select})
},
//删除单条产品
deleteOneProduct:function (index) {
//根据索引删除productList的记录
this.productList.splice(index,1);
},
полный код
образ в стиле
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.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%;
}
</style>
</head>
<body>
<div class="page-shopping-cart" id="shopping-cart">
<h4 class="cart-title">购物清单</h4>
<div class="cart-product-title clearfix">
<div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}" @click="selectProduct(isSelectAll)"></span>全选</div>
<div class="td-product fl">商品</div>
<div class="td-num fl">数量</div>
<div class="td-price fl">单价(元)</div>
<div class="td-total fl">金额(元)</div>
<div class="td-do fl">操作</div>
</div>
<div class="cart-product clearfix">
<table>
<tbody>
<!--遍历的时候带上索引-->
<tr v-for="(item,index) in productList">
<td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td>
<td class="td-product"><img :src="item.pro_img" width="98" height="98">
<div class="product-info">
<h6>{{item.pro_name}}</h6>
<p>品牌:{{item.pro_brand}} 产地:{{item.pro_place}}</p>
<p>规格/纯度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p>
<p>配送仓储:{{item.pro_depot}}</p>
</div>
<div class="clearfix"></div>
</td>
<td class="td-num">
<div class="product-num">
<a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num>0?item.pro_num--:''"><span></span></a>
<input type="text" class="num-input" v-model="item.pro_num">
<a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>
</div>
</td>
<td class="td-price">
<p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>
</td>
<td class="td-total">
<p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>
</td>
<td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">删除</a></td>
</tr>
</tbody>
</table>
</div>
<div class="cart-product-info">
<a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>删除所选商品</a>
<a class="keep-shopping" href="#"><span></span>继续购物</a>
<a class="btn-buy fr" href="javascript:;">去结算</a>
<p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p>
<p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品总计(不含运费):</p>
</div>
</div>
</body>
<script src="../vue.min.js"></script>
<script>
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(){
//如果长度为0,直接返回false
if(this.productList.length===0){
return false;
}
//如果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<len;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);
})
}
})
</script>
</html>
5.todoList
текущий результат
Принцип анализа и реализации
Прежде всего, лучше сначала написать макет, и ввести vue, и подготовить экземпляр vue.Это не так много, код выглядит следующим образом
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
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;}
</style>
</head>
<body>
<div id="app" class="main">
<h2>小目标列表</h2>
<div class="list">
<h3>添加小目标</h3>
<input type="text" class="text-keyword" placeholder="输入小目标后,按回车确认"/>
<p>共有N个目标</p>
<p>
<input type="radio" name="chooseType" checked="true"/><label>所有目标</label>
<input type="radio" name="chooseType"/><label>已完成目标</label>
<input type="radio" name="chooseType"/><label>未完成目标</label>
</p>
</div>
<ul>
<li class="li1">
<div>
<span class="type-span"></span>
<span>html5</span>
<span class="close">X</span>
</div>
</li>
<li class="li1">
<div>
<span class="type-span"></span>
<span>css3</span>
<span class="close">X</span>
</div>
</li>
</ul>
</div>
</body>
<script src="vue2.4.2.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
},
computed:{
},
methods:{
}
});
</script>
</html>
С макетом это эквивалентно наличию скелета.Следующие функции реализованы одна за другой
шаг 1
Введите и нажмите Enter, еще одна запись. Текст записи ниже также изменится
Прежде всего, если в большом поле ввода нажать Enter, чтобы добавить запись, то поле ввода должно быть связано со значением и методом добавления записи.
код показывает, как показано ниже:
Затем следует также изменить следующую запись, поэтому следующая запись также должна помочь со значением, потому что записей может быть несколько, это значение является массивом, вы также можете видеть, что запись не только имя, но и запись завершена, поэтому значение связанной записи должно быть массивом объектов! код показывает, как показано ниже
Наконец, запишите текстизменить. Это длина текущей записи!
Чтобы выделить то, что я изменил, я публикую только измененную часть кода, и каждый может легко узнать, что я изменил, посмотрев на макет выше! То же самое касается следующего!
HTML-код
<!--利用v-model把addText绑定到input-->
<input type="text" class="text-keyword" placeholder="输入小目标后,按回车确认" @keyup.13='addList' v-model="addText"/>
<p>共有{{prolist.length}}个目标</p>
<!--v-for遍历prolist-->
<li class="li1" v-for="list in prolist">
<div>
<span class="type-span"></span>
<span>{{list.name}}</span>
<span class="close">X</span>
</div>
</li>
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) для хранения пролиста. При обходе он больше не просматривает пролист, а просматривает новый список. Изменение также меняет newList.
Затем, когда все цели выбраны, отображается весь список proList, присваивая список proList новому списку.
Затем при выборе всех выполненных целей отображать в пролисте только те цели, чей статус истинен, и назначать элементы, чей статус истинен в пролисте, в новый список.
Наконец, когда все незавершенные цели выбраны, отображаются только цели со статусом false, а элементы со статусом false в пролисте назначаются newList.
код показывает, как показано ниже
html
<ul>
<li class="li1" v-for="list in newList">
<div>
<span class="status-span"></span>
<span>{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
</li>
</ul>
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!
Последней записью изменения текста является запись количества элементов со статусом false в prolist и количества элементов со статусом true в prolist.
HTML-код
<!--如果noend等于0,就是全部完成了就显示‘全部完成了’,如果没有就是显示已完成多少条(prolist.length-noend)和未完成多少条(noend)-->
<p>共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}</p>
<ul>
<li class="li1" v-for="(list,index) in newList">
<div>
<span class="status-span" @click="list.status=!list.status" :class="{'status-end':list.status}"></span>
<span>{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
</li>
</ul>
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
Дважды щелкните текст, и появится поле ввода, где вы можете ввести текст. Если вы нажмете Enter или потеряете фокус, текст будет изменен. Если вы нажмете ESC, исходный текст будет восстановлен.
Прежде всего. Дважды щелкните поле ввода, он должен дважды щелкнуть текст, установить имя класса в текущий Li ('eidting
'), а затем напишите стиль. Когда имя класса появляется в li, появляется поле ввода, а остальное содержимое скрыто.
Затем. Ввести или потерять фокус, изменить текст. Для этого нужна только одна операция, то есть поставить имя класса ('eidting
') очистить. Тогда поле ввода будет скрыто, а другой контент будет отображаться!
Наконец, нажмите ESC, чтобы восстановить исходный текст, то есть, когда появится поле ввода, используйте переменную ('beforeEditText
') сначала сохраните текущий контент, затем нажмите ESC, переменная ('beforeEditText
') присваивается значению текущей операции!
код показывает, как показано ниже:
html
<ul>
<li class="li1" v-for="(list,index) in newList" :class="{'eidting':curIndex===index}">
<div>
<span class="status-span" @click="list.status=!list.status" :class="{'status-end':list.status}"></span>
<span @dblclick="curIndex=index">{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
<input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited'/>
</li>
</ul>
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
<input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited' v-focus/>
полный код
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
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;}
</style>
</head>
<body>
<div id="app" class="main">
<h2>小目标列表</h2>
<div class="list">
<h3>添加小目标</h3>
<input type="text" class="text-keyword" placeholder="输入小目标后,按回车确认" @keyup.13='addList' v-model="addText"/>
<!--如果noend等于0,就是全部完成了就显示‘全部完成了’,如果没有就是显示已完成多少条(prolist.length-noend)和未完成多少条(noend)-->
<p>共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}</p>
<p>
<input type="radio" name="chooseType" checked="true" @click='chooseList(1)'/><label>所有目标</label>
<input type="radio" name="chooseType" @click='chooseList(2)'/><label>已完成目标</label>
<input type="radio" name="chooseType" @click='chooseList(3)'/><label>未完成目标</label>
</p>
</div>
<ul>
<li class="li1" v-for="(list,index) in newList" :class="{'eidting':curIndex===index}">
<div>
<span class="status-span" @click="changeType(index)" :class="{'status-end':list.status}"></span>
<span @dblclick="curIndex=index">{{list.name}}</span>
<span class="close" @click='delectList(list)'>X</span>
</div>
<input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited' v-focus/>
</li>
</ul>
</div>
</body>
<script src="vue.min.js"></script>
<script type="text/javascript">
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();
}
}
}
});
</script>
</html>
6. Резюме
Ну вот и готовы три небольших примера! Не смотрите статью так долго, она на самом деле базовая, может быть, я более многословен! Если вы знакомы с этими небольшими примерами, я считаю, что использовать Vue для создания проектов также легко. Базовая грамматика здесь. С основами не составит труда научиться продвинутому письму! Если в будущем мне будет чем поделиться, я продолжу делиться. Последняя старая поговорка, если вы чувствуете, что я написал что-то не так или написал плохо, подскажите, пожалуйста!
------------------------- Великолепная разделительная линия --------------------
Хотите узнать больше, обратите внимание на мой публичный аккаунт WeChat: В ожидании книжного магазина