vue ref引用 修饰符sync

请添加图片描述
vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。这里用sync实现,只是给大家提供一个思路,让其明白他的实现原理,可能有其它复杂的功能适用sync。

这只是一个简单的例子,看完这个不知你是不觉得有个指令跟这个很相似,v-model?对,就是v-model在组件上使用的时候。

这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

vue的实例属性和方法

除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。

ref 属性

1、ref 加在普通的元素上,用this.ref.name 获取到的是dom元素

2、ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。

3、如何利用 v-for 和 ref 获取一组数组或者dom 节点

this.$refs 获取了所有设置ref属性的元素(如有重名那么会被覆盖)

如果是普通的元素那返回的是一个普通的dom,如果ref放在vue组件里,那么返回的是一个vue对象,这个对象包含了这个组件的各种信息

<template>
  <div>
    <NotepadHeader/>
    <div class="empty" v-show="!isShow">
      <div class="no-data">
        <img src="@/assets/no-data.png" class="no-data-img"/>
        <span class="no-data-text">暂无数据</span>
      </div>
    </div>
    <div class="notepad-list" v-show="isShow">
      <div v-for="(note,index) of this.$store.state.notepadList" v-bind:key="index" class="notepad-list-item">
        <div class="notepad-list-item-content">{{note.thing}}<button @click="delItem(note.id)" style="float:right ">del</button></div>
        <div class="notepad-list-item-label">
          {{note.address}} {{note.time}}
        </div>
      </div>
    </div>
    <div class="add-item" @click="addItem">
      <img class="add-item-icon" src="@/assets/add.png" style="border-radius: 50%"/>
    </div>
    <NotepadFooter/>
  </div>
</template>

<script>
import NotepadHeader from '@/components/NotepadHeader'
import NotepadFooter from '@/components/NotepadFooter'
export default {
  name: 'StartPage',
  components: {
    NotepadHeader,
    NotepadFooter
  },
  data () {
    return {
      isShow: this.$store.state.notepadList.length > 0
    }
  },
  methods: {
    addItem () {
      this.$router.push('/add')
    },
    delItem (id) {
      for (let i = 0; i < this.$store.state.notepadList.length; i++) {
        if (this.$store.state.notepadList[i].id === id) {
          console.log(i)
          this.$store.state.notepadList.splice(i, 1)
        }
      }
    },
    editItem (id) {
      for (let i = 0; i < this.$store.state.notepadList.length; i++) {
        if (this.$store.state.notepadList[i].id === id) {
          console.log(i)
          this.$store.state.notepadList.splice(i, 1)
        }
      }
    }
  },
  watch: {
  }
}

</script>

<style scoped>
  .no-data {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .no-data-img {
    display: block;
    margin-top: 30px;
    width: 50%;
  }
  .no-data-text {
    margin-top: 10px;
    font-size: 20px;
    color: #999;
  }
  .add-item {
    z-index: 100;
    width: 60px;
    height: 60px;
    position: absolute;
    bottom: 30px;
    left: 50%;
    transform: translate(-50%);
  }
  .add-item-icon {
    display: block;
    width: 100%;
    height: 100%;
  }
  .notepad-list-item{
     height: 100px;
     background: #eee;
     margin: 10px 20px;
   }
  .notepad-list-item-content{
    position: relative;
    left: 10px;
    top: 10px;
    color: #222 ;
  }
  .notepad-list-item-label{
    position: relative;
    left: 50px;
    top: 50px;
    color: #aaa;
  }
</style>
<template>
  <div>
    <NotepadHeader/>
    <div class="empty" v-show="!isShow">
      <div class="no-data">
        <img src="@/assets/no-data.png" class="no-data-img"/>
        <span class="no-data-text">暂无数据</span>
      </div>
    </div>
    <div class="notepad-list" v-show="isShow">
      <div v-for="(note,index) of this.$store.state.notepadList" v-bind:key="index" class="notepad-list-item">
        <div class="notepad-list-item-content">{{note.thing}}<button @click="delItem(note.id)" style="float:right ">del</button></div>
        <div class="notepad-list-item-label">
          {{note.address}} {{note.time}}
        </div>
      </div>
    </div>
    <div class="add-item" @click="addItem">
      <img class="add-item-icon" src="@/assets/add.png" style="border-radius: 50%"/>
    </div>
    <NotepadFooter/>
  </div>
</template>

<script>
import NotepadHeader from '@/components/NotepadHeader'
import NotepadFooter from '@/components/NotepadFooter'
export default {
  name: 'StartPage',
  components: {
    NotepadHeader,
    NotepadFooter
  },
  data () {
    return {
      isShow: this.$store.state.notepadList.length > 0
    }
  },
  methods: {
    addItem () {
      this.$router.push('/add')
    },
    delItem (id) {
      for (let i = 0; i < this.$store.state.notepadList.length; i++) {
        if (this.$store.state.notepadList[i].id === id) {
          console.log(i)
          this.$store.state.notepadList.splice(i, 1)
        }
      }
    },
    editItem (id) {
      for (let i = 0; i < this.$store.state.notepadList.length; i++) {
        if (this.$store.state.notepadList[i].id === id) {
          console.log(i)
          this.$store.state.notepadList.splice(i, 1)
        }
      }
    }
  },
  watch: {
  }
}

</script>

<style scoped>
  .no-data {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .no-data-img {
    display: block;
    margin-top: 30px;
    width: 50%;
  }
  .no-data-text {
    margin-top: 10px;
    font-size: 20px;
    color: #999;
  }
  .add-item {
    z-index: 100;
    width: 60px;
    height: 60px;
    position: absolute;
    bottom: 30px;
    left: 50%;
    transform: translate(-50%);
  }
  .add-item-icon {
    display: block;
    width: 100%;
    height: 100%;
  }
  .notepad-list-item{
     height: 100px;
     background: #eee;
     margin: 10px 20px;
   }
  .notepad-list-item-content{
    position: relative;
    left: 10px;
    top: 10px;
    color: #222 ;
  }
  .notepad-list-item-label{
    position: relative;
    left: 50px;
    top: 50px;
    color: #aaa;
  }
</style>

NotepadFooter.vue

<template>
  <div class="footer">
  </div>
</template>

<script>
export default {
  name: 'NotepadFooter'
}
</script>

<style scoped>
  .footer {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 60px;
    background-image: linear-gradient(45deg, #6699ff, #00cc99);
  }
</style>

NotepadHeader.vue

<template>
  <div class="header">
    <span class="title">记事本</span>
  </div>
</template>

<script>
export default {
  name: 'NotepadHeader'
}
</script>

<style scoped>
  .header {
    width: 100%;
    height: 80px;
    background-image: linear-gradient(45deg, #6699ff, #00cc99);
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
  }
  .title {
    color: #fff;
    font-size: 26px;
  }
</style>

请添加图片描述请添加图片描述请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值