vue(2019/7/15)

vue实现照片选择或者拍照功能

照片格式校验,

图片质量压缩,

图片尺寸压缩,

图片离线保存,

图片base64编码互转

<template>
<div class="photo-list">
<hips-view
ref="photoList"
header-fixed
sub-header-fixed
header-height="48"
:sub-header-height="subHeaderHeight"
footer-height="48"

<div
slot="header"
style="width:100%"

<hips-nav-bar
:title="headerTitle"

<div slot="left">
<hips-button
style="margin-left:10px"
@click="goBack"

返回
</hips-button>
</div>
<div slot="right">
<hips-button
v-if="orderStatus===1"
style="margin-right:10px"
@click="uploadImg"

上传
</hips-button>
<hips-button
v-if="orderStatus===0"
style="margin-right:10px"
@click="saveImg"

保存
</hips-button>
</div>
</hips-nav-bar>
</div>
<div
slot="sub-header"
class="sub-header"

<div class="content-item">
<div
v-if="orderStatus===0"
class="content-item-checked"

<hips-checkbox
v-model="checked"
:border="false"
class="content-item-components"

已确认录入完整信息
</hips-checkbox>
</div>
<div class="content-title">
<span v-if="orderStatus===1|orderStatus===0">
数量({{ photoDataList.length }}/30)
</span>
<span v-if="orderStatus===2">
数量({{ photoDataList.length }})
</span>
</div>
<hips-button
v-if="deleteFileSelected.length < 1&&orderStatus!==2"
class="read-only-delete"
size="small"
@click="deleteNull"

删除
</hips-button>
<hips-button
v-if="deleteFileSelected.length>0&&orderStatus!==2"
size="small"
type="warning"
@click="deleteFile"

删除
</hips-button>
<hips-button
v-if="orderStatus===2"
class="back-to-top"
size="small"
@click="backToTop"

回到顶部
</hips-button>
</div>
</div>
<div
class="content"
:class="[orderStatus!==0?'content-12':'content-0']"

<hips-scroll
ref="scroll"

<div
v-if="photoDataList.length"
class="list"

<ol class="list-ol">
<li
v-for="(item, index) in photoDataList"
:key="index"
class="list-li"

<label
v-if="item.status.canSelect"
class="checkbox-label"

<span class="checkbox-lists">
<input
v-model="item.status.selectValue"
class="checkbox-list-input"
type="checkbox"
@change="checkChange"
@click="select(item)"

<span class="checkbox-list-span" />
</span>
</label>
<img
v-if="item.status.read"
ref="showImg"
:src="changeUrl(item.file)"
class="show-img"
@click="showPreviewer(index)"

<img
v-if="item.status.unUpload"
:src="upload"
alt="图片未上传"
class="upload"

</li>
</ol>
</div>

<img
:src="yasuohou"
alt=""

</hips-scroll>
</div>
<div
slot="footer"
class="footer"

<div class="left">
<label
v-if="photoDataList.length < 30"
for="picture"
class="button"

  • 相册照片
    </label>
    <label
    v-else
    class="only-read-button"
  • 相册照片
    </label>
    <input
    id="picture"
    type="file"
    @change="change"

</div>
<div class="right">
<label
v-if="photoDataList.length < 30"
id="camera"
class="button"

  • 新拍照片
    </label>
    <label
    v-else
    class="only-read-button"
  • 新拍照片
    </label>
    <input
    id="camera"
    type="file"
    accept="image/*"
    capture="camera"

</div>
</div>
</hips-view>
</div>
</template></pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="javascript" cid="n8" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><script>
import { NavBar, Button, Tabs, Tab, View, Scroll, Input, Group, Cell, Checkbox , CheckboxGroup, Previewer } from "@hips/vue-ui";
import edit from "../../../assets/editor.png"
import add from "../../../assets/add-fill.png"
import upload from "../../../assets/upload.png"
import DB from "@/indexDB"
// import { uuid } from "@/utils"

import Vue from "vue"
Vue.use(Previewer);
export default {
name: "PhotoList",
components: {
[View.name]: View,
[Tabs.name]: Tabs,
[Tab.name]: Tab,
[NavBar.name]: NavBar,
[Button.name]: Button,
[Scroll.name]: Scroll,
[Input.name]: Input,
[Group.name]: Group,
[Cell.name]: Cell,
[Checkbox.name]: Checkbox,
[CheckboxGroup.name]: CheckboxGroup,
[Previewer.name]: Previewer,
},
data(){
return{
subHeaderHeight: 100,
headerTitle: "照片一览",
checked: false,
edit: edit,
add: add,
upload: upload,
mimeTypes: [ 'image/png', 'image/jpeg' ], // 图片类型
selectValue: false,
photoDataList: [], // 数据列表数组
imgUrl: "",
canSelect: false,
unUpload: false,
orderStatus: 0, // 0 工单还未提交, 1 工单已经提交,但还未点击完成派工时 2 完成派工后
imageSet: [], // 展示的照片源
deleteFileSelected: [], // 已经勾选删除的照片数组
yasuohou: "",
files: [],
}
},
beforeRouteEnter(to,from,next){
next((vm) => {
if(vm.orderStatus !== 0) {
vm.subHeaderHeight = 38
vm.resizePage();
}
vm.photoDataList = [];
let PhotoAlbum = {
name: "album",
store: "photo1",
id: "timeStamp",
db: null,
}
DB.openDB(PhotoAlbum, PhotoAlbum.name, 1, PhotoAlbum.store, PhotoAlbum.id).then((DBres) => { // 将当前角色的menu存在indexedDB中
DB.readAll(DBres.db, PhotoAlbum.store).then((res)=> {
for(let i = 0; i < res.length; i ++){
let status = {};
if(vm.orderStatus === 0) {
status = {
canSelect: true,
unUpload: true,
selectValue: false,
read: true, // 是否是从本地文件夹读取的图片
}
}
if(vm.orderStatus === 1) {
status = {
canSelect: false,
unUpload: true,
selectValue: false,
read: true, // 是否是从本地文件夹读取的图片
}
}
if(vm.orderStatus === 2) {
status = {
canSelect: false,
unUpload: false,
selectValue: false,
read: true, // 是否是从本地文件夹读取的图片
}
}
res[i].status = status;
}
vm.photoDataList = res;
})
})
})
},

watch: {
photoDataList() {
this.deleteFileSelected = this.photoDataList.filter((item) => {
return item.status.selectValue === true;
})
},
files() {
console.log("files", this.files)
},
},
methods: {
showPreviewer (index) { // 图片预览
this.imageSet = [];
for(let i = 0; i < this.photoDataList.length; i ++) {
this.imageSet.push({
msrc: "",
src: window.URL.createObjectURL(this.photoDataList[i].file),
desc: this.photoDataList[i].file.name,
})
}
this.hips.previewer.show({ imageSet: this.imageSet, options: { index: index, }, onClose: () => { console.log(`onClose`) }, onIndexChange: (index) => { console.log(`onIndexChange index ={index}) }, }) }, saveImg() { // 保存图片 let PhotoAlbum = { name: "album", store: "photo1", id: "timeStamp", db: null, } DB.openDB(PhotoAlbum, PhotoAlbum.name, 1, PhotoAlbum.store, PhotoAlbum.id).then((DBres) => { // 将当前角色的menu存在indexedDB中 DB.update(DBres.db, PhotoAlbum.store, this.photoDataList); }) }, uploadImg() { // 上传图片 ​ }, typeCheck(file) { // 图片类型校验 let flag = false; let fileTypes = ".jpg"; let filePath = file.value; //当括号里面的值为0、空字符、false 、null 、undefined的时候就相当于false if(filePath){ let isNext = false; let fileEnd = filePath.substring(filePath.indexOf(".")); if (fileTypes === fileEnd) { isNext = true; flag= true; } if (!isNext){ alert('不接受此文件类型,请上传jpg格式文件'); file.value = ""; flag = false; } } return flag; }, sizeCheck(file) { let filePath = file.value; let that = this; that.files = []; let fileTypes = ".jpg"; if(filePath) { let isNext = false; let fileEnd = filePath.substring(filePath.indexOf(".")); if (fileTypes === fileEnd) { isNext = true; } if (!isNext){ // 类型检测 that.$hips.dialog({ title: "提示", content: "不接受此文件类型,请上传jpg格式文", okText: '确定', cancelText: '取消', closable: false, }) file.value = ""; return; } let filePic = file.files[0]; //读取图片数据 let reader = new FileReader(); reader.onload = function (e) { let data = e.target.result; let image = new Image(); //加载图片获取图片真实宽度和高度 image.src = data; setTimeout(() => { if(image.width < 640 | image.height < 480) { // 分辨率不可小于640*480 // alert("照片添加失败,分辨率不可小于640*480"); let back = () => { that.files = []; file.value = ""; return; } that.$hips.dialog.confirm({ title: "提示", content: "照片添加失败,分辨率不可小于640*480", okText: '确定', cancelText: '取消', closable: false, onOk: back, }); } if(image.width >= 640 && image.height >= 480&& image.width <= 1920 && image.height <= 1080) { // 分辨率不可大于1920*1080 if(file.files[0].size/1024 > 150) { // 压缩大小 let canvasWidth = image.width; let canvasHeight = image.height; let canvas = document.createElement('canvas');//生成canvas let ctx = canvas.getContext('2d'); canvas.width = canvasWidth; // 创建节点属性 canvas.height = canvasHeight; let anw = document.createAttribute('width'); anw.nodeValue = canvasWidth; let anh = document.createAttribute('height'); anh.nodeValue = canvasHeight; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight); //图像质量,值越小,所绘制出的图像越模糊 let quality = 0.05; let size = 0; let lastObj; while(size < 150) { if(obj) { lastObj = obj; } let base64String = canvas.toDataURL('image/jpeg', quality); let obj = that.base64ToImg(base64String, file.files[0].name); size = Number((obj.size / 1024).toFixed(2)); quality = Number((quality + 0.05).toFixed(2)); } that.files.push(lastObj); file.value = ""; } else { that.files.push(file.files[0]); file.value = ""; } } if(image.width > 1920 | image.height > 1080) { // 压缩分辨率 let scale = Number((image.width / image.height).toFixed(2)); let standard = Number((1920 / 1080).toFixed(2)); let canvasWidth, canvasHeight; if( scale > standard ) { canvasWidth = image.width; canvasHeight = Number((image.width / scale).toFixed(2)); } else { canvasHeight = image.height; canvasWidth = Number((image.height * scale).toFixed(2)); } let canvas = document.createElement('canvas');//生成canvas let ctx = canvas.getContext('2d'); canvas.width = canvasWidth; // 创建节点属性 canvas.height = canvasHeight; let anw = document.createAttribute('width'); anw.nodeValue = canvasWidth; let anh = document.createAttribute('height'); anh.nodeValue = canvasHeight; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight); //图像质量,值越小,所绘制出的图像越模糊 let quality = 0.95; let base64String = canvas.toDataURL('image/jpeg', quality); let obj = that.base64ToImg(base64String, file.files[0].name); if((obj.size / 1024) < 150) { that.files.push(obj); file.value = ""; } else { // 压缩大小 let quality = 0.05; let size = 0; let lastObj; while(size < 150) { if(obj) { lastObj = obj; } let base64String = canvas.toDataURL('image/jpeg', quality); let obj = that.base64ToImg(base64String, file.files[0].name); size = Number((obj.size / 1024).toFixed(2)); quality = Number((quality + 0.05).toFixed(2)); } that.files.push(lastObj); file.value = ""; return; } } let arr = []; for(let i = 0; i < that.files.length; i ++) { let pictureObj = {}; let status = { canSelect: true, unUpload: true, selectValue: false, read: true, // 是否是从本地文件夹读取的图片 } pictureObj.status = status; pictureObj.file = that.files[i]; pictureObj.timeStamp = (new Date()).valueOf(); arr.push(pictureObj); } that.photoDataList = [ ...that.photoDataList, ...arr ] ; }, 1) }; reader.readAsDataURL(filePic); } else { this.$hips.dialog } }, change(e) { this.sizeCheck(e.target); // this.imgToBase64(this.photoDataList); // indexedDB不能直接存储base64 }, imgToBase64(imgList) { // 图片base64编码 for(let i = 0; i < imgList.length; i ++) { let reader = new FileReader(); reader.readAsDataURL(imgList[i].file); reader.onload = (e) => { imgList[i].status.base64 = e.target.result; } } }, base64ToImg(base64, filename) { // 图片base64转码 let dataURLtoFile = (dataurl, filename = 'file') => { if(!dataurl) return; let arr = dataurl.split(',') let mime = arr[0].match(/:(.*?);/)[1] let suffix = mime.split('/')[1] let bstr = atob(arr[1]) let n = bstr.length let u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new File([ u8arr ],{filename}.{suffix}, { type: mime, }) } let imgFile = dataURLtoFile(base64, filename); if(!imgFile) return; // return window.URL.createObjectURL(imgFile); return imgFile; }, changeUrl(item) { // 获取图片地址 let a = window.URL.createObjectURL(item); return a; }, deleteFile() { // 删除图片 let back = ()=> { console.log("要删除的图片", this.photoDataList); let PhotoAlbum = { name: "album", store: "photo1", id: "name", db: null, } for(let i = 0; i < this.photoDataList.length; i ++) { if(this.photoDataList[i].status.selectValue) { let mainKey = this.photoDataList[i].timeStamp; DB.openDB(PhotoAlbum, PhotoAlbum.name, 1, PhotoAlbum.store, PhotoAlbum.id).then((DBres) => { // 将当前角色的menu存在indexedDB中 DB.remove(DBres.db, PhotoAlbum.store, mainKey); }) } } let arr = []; for(let i = 0; i < this.photoDataList.length; i ++) { if(!this.photoDataList[i].status.selectValue) { arr.push(this.photoDataList[i]); } } this.photoDataList = []; for(let i = 0; i < arr.length; i ++) { this.$set(this.photoDataList, i, arr[i]); } } this.$hips.dialog.confirm({ title: '提示', content:请确认是否删除这{this.deleteFileSelected.length}张照片`, okText: '确定', cancelText: '取消', closable: false, onOk: back, }); // this.forceUpdate();
// this.resizePage();
},
deleteNull() { // 未勾选删除
this.hips.dialog.confirm({ title: '提示', content: '请先勾选需删除的照片', okText: '确定', cancelText: '取消', closable: false, }); }, backToTop() { // 回到顶部 this.refs.scroll.scrollTo(0, 0, 700, "easing");
},
goBack() { // 返回上页面
if(this.orderStatus === 1) {
let back = ()=> {
this.router.push({ name:"Order", params: { checked: this.checked, }, }) } this.hips.dialog.confirm({
title: '提示',
content: '数据未被保存,是否继续返回?',
okText: '确定',
cancelText: '取消',
closable: false,
onOk: back,
onCancel() {},
});
}
if(this.orderStatus === 0 | this.orderStatus === 2) {
this.router.push({ name:"Order", params: { checked: this.checked, }, }) } }, select(item) { // 选择要删除图片 item.status.selectValue = !item.status.selectValue; this.deleteFileSelected = this.photoDataList.filter((item) => { return item.status.selectValue === true; }) console.log("select", this.deleteFileSelected); }, checkChange() { // 更新checkbox视图 this.forceUpdate(); // 数据改变更新视图
},
resizePage () { // 刷新页面(未使用)
this.refs.photoList.emit('hips-view:resize');
},
},
}
</script></pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="css" cid="n9" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><style lang="stylus" scoped>
// 选择框样式 start
.checkbox-list-input {
display: none;
}
.checkbox-list-input:checked + .checkbox-list-span {
background-color: #c30;
border-color: #c30;
}
.checkbox-list-input:checked + .checkbox-list-span::after {
border-color: #fff;
transform: rotate(45deg) scale(1);
}
.checkbox-list-input[disabled] + .checkbox-list-span {
background-color: #d9d9d9;
border-color: #ccc;
}
.checkbox-list-span {
display: inline-block;
background-color: #fff;
border-radius: 100%;
border: 1px solid #ccc;
position: relative;
width: 26px;
height: 26px;
vertical-align: middle;
}
.checkbox-list-span::after {
border: 2px solid transparent;
border-left: 0;
border-top: 0;
content: "";
top: 4px;
left: 9px;
position: absolute;
width: 6px;
height: 16px;
transform: rotate(45deg) scale(0);
transition: transform .2s;
}
// 选择框样式 end
.photo-list {

.hips-view__sub-header {
border-bottom none
}
.sub-header {
.content-item {
margin 10px
.content-item-checked {
margin-top 10px
margin-bottom 10px
text-align center
background #fff
/deep/.hips-checkbox {
color #009999
}
/deep/.hips-checkbox__checked--active {
background #c30
}
.content-item-components {
display inline-block
}
}
.content-title {
display inline-block
height 30px
width 100%
line-height 30px
text-align center
margin-right -70px
}
.delete, .back-to-top {
background #ff6600
color #ffffff
}
.read-only-delete {
background #e4e4e4
color #000
}
}
}

.content-0 {
height: calc( 100vh - 218px);
}
.content-12 {
height: calc( 100vh - 166px);
}
.content {
margin: 10px;
border: 1px solid #ccc;
border-radius: 10px;
background: #fff;

.hips-row:after {
display: none;
}
.list {
.list-ol {
display flex
flex-flow row wrap
// justify-content space-around
align-items flex-start
}
.list-li {
position relative
margin-top 10px
margin-left 8px
.checkbox-lists {
position absolute
right -4px
top -6px
}
.show-img {
width 100px
height 100px
padding 2px
border 2px dashed #cccccc
}
.upload {
position absolute
width 30px
height 30px
bottom -2px
right -4px
background #fff
border-radius 50% 50%
}
}
}
}
.footer {
display flex
flex 1
height 100%
.hips-view__sub-header {
border-bottom none
}
.sub-header {
.content-item {
margin 10px
.content-item-checked {
margin-top 10px
margin-bottom 10px
text-align center
background #fff
/deep/.hips-checkbox {
color #009999
}
/deep/.hips-checkbox__checked--active {
background #c30
}
.content-item-components {
display inline-block
}
}
.content-title {
display inline-block
height 30px
width 100%
line-height 30px
text-align center
margin-right -70px
}
.delete, .back-to-top {
background #ff6600
color #ffffff
}
.read-only-delete {
background #e4e4e4
color #000
}
}
}
.content-0 {
height: calc( 100vh - 218px);
}
.content-12 {
height: calc( 100vh - 166px);
}
.content {
margin: 10px;
border: 1px solid #ccc;
border-radius: 10px;
background: #fff;
>>>.hips-row:after {
display: none;
}
.list {
.list-ol {
display flex
flex-flow row wrap
// justify-content space-around
align-items flex-start
}
.list-li {
position relative
margin-top 10px
margin-left 8px
.checkbox-lists {
position absolute
right -4px
top -6px
}
.show-img {
width 100px
height 100px
padding 2px
border 2px dashed #cccccc
}
.upload {
position absolute
width 30px
height 30px
bottom -2px
right -4px
background #fff
border-radius 50% 50%
}
}
}
}
.footer {
display flex
flex 1
height 100%
line-height 48px
input {
display inline-block
width 0
height 0
}
.left {
width 50%
text-align center
.button {
display inline-block
height 40px
width: 90%
line-height 40px
background #ff6600
color #ffffff
}
.only-read-button {
background #e4e4e4
color #000
height 40px
width: 90%
line-height 40px
display inline-block
}
}
.right {
width 50%
text-align center
.button {
display inline-block
height 40px
line-height 40px
width: 90%
background #cc3300
color #ffffff
}
.only-read-button {
background #e4e4e4
color #000
height 40px
width: 90%
line-height 40px
display inline-block
}
}
}
}
</style></pre>

效果展示

image.png

vue父子组件传参

// dom部分

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n14" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><div id="app">
<my-header :l="list"></my-header>
</div></pre>

// vue父子组件如何传参

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="javascript" cid="n16" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">var oApp = new Vue({
el: "#app",
data: {
list: ["第1项", "第2项", "第3项"]
},
components: {
'my-header': {
template: <div> <h2 ref>{{nowMessage}}</h2> <ul> <li v-for="item in l">{{item}}</li> <my-nav @changEvent="getChildContent"></my-nav> </ul> </div>,
data: function() {
return {
message: "hello world!!!",
nowMessage: this.message //单向数据流,数据操做,refDOM操作 ,.native
}
},
methods: {
getChildContent: function(arg) {
console.log(arg);
this.nowMessage = arg;
}
},
props: ['l'], //父组件向子组件进行通信操作
components: {
'my-nav': { //子组件向父组件传值
template: <ul> <li @click="getContent">"yes, I'm fine"</li> </ul>,
methods: {
getContent: function(ev) {
this.$emit("changEvent", ev.target.innerText);
}
}
}
}
}
}
})</pre>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容