Vue [Day4]

这篇具有很好参考价值的文章主要介绍了Vue [Day4]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

组件化开发 & 根组件

Vue [Day4],vue.js,前端
Vue [Day4],vue.js,前端


Vue [Day4],vue.js,前端


App.vue

<template>
  <div class="App">
    <div class="box" @click="fn"></div>
  </div>
</template>

<script>
// 导出的是当前组件的配置项
// 里面可以提供 data(特殊) methods computed watch 生命周期八大钩子
export default {
  created () {
    console.log('我是created')
  },
  methods: {
    fn () {
      alert('你好')
    }
  }
}
</script>

<style lang="less">
/* 让style支持less
   1. 给style加上 lang="less"
   2. 安装依赖包 less less-loader
      yarn add less less-loader -D (开发依赖)
*/
.App {
  width: 400px;
  height: 400px;
  background-color: pink;
  .box {
    width: 100px;
    height: 100px;
    background-color: skyblue;
  }
}
</style>


普通组件的注册使用

局部注册

Vue [Day4],vue.js,前端

components/HmFooter.vue

<template>
  <div class="hm-header">
    我是hm-header
  </div>
</template>

<script>
export default {

}
</script>

<style>
.hm-header{
    height: 100px;
    line-height: 100px;
    text-align: center;
    font-size: 30px;
    background-color: #cdcf48;
}
</style>

App.vue

<template>
  <div class="App">

<!-- 使用,直接当成html标签使用 -->
<!-- 组件命名规范,大驼峰命名法 -->


<!-- 头部组件 -->
<HmHeader></HmHeader>  

<!-- 主体组件 -->
<HmMain></HmMain>

<!-- 底部组件 -->
<HmFooter></HmFooter>

  </div>
</template>

<script>
// 导入
import HmFooter from './components/HmFooter.vue';
import HmHeader from './components/HmHeader.vue';
import HmMain from './components/HmMain.vue';

export default {

  // 局部注册
components:{
  // '组件名':'组件对象
  
  HmHeader:HmHeader,
  HmFooter,// 同名可简写
  HmMain,
}
}
</script>

<style>
.App{
  width: 600px;
  height: 700px;
  background-color:rgb(0, 234, 255);
  padding: 20px;
  margin: 0 auto;
}
</style>

全局注册

Vue [Day4],vue.js,前端


HmButton.vue

<template>
  <button class=".hm-button">通用按钮</button>
</template>

<script>
export default {

}
</script>

<style>
.hm-button{
    height: 50px;
    line-height: 50px;
    padding: 0 20px;
    background-color: #ca2a50;
    border-radius: 5px;
}
</style>

main.js

// 文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
import Vue from 'vue'
import App from './App.vue'

// 1.导入的代码,都写在上面,书写规范
import HmButton from './components/HmButton'
Vue.config.productionTip = false

// 2.进行全局注册
// Vue.component(组件名,组件注册)
Vue.component('HmButton', HmButton)


new Vue({

  render: (createElement) => {

    return createElement(App)
  }
}).$mount('#app')


HmFooter.vue
<template>
    <div class="hm-footer">
      我是hm-footer

      <!-- 直接用 -->
      <HmButton></HmButton>

    </div>
  </template>
  
  <script>
  export default {
  
  }
  </script>
  
  <style>
  .hm-footer{
      height: 100px;
      line-height: 100px;
      text-align: center;
      font-size: 30px;
      background-color: #6848cf;
  }
  </style>

两种注册方式总结

Vue [Day4],vue.js,前端

【案例】—— 小兔鲜 组件拆分

Vue [Day4],vue.js,前端

Vue [Day4],vue.js,前端

组件的三大组成部分

Vue [Day4],vue.js,前端

组件的样式冲突 scoped

Vue [Day4],vue.js,前端

<style scoped>

</style>

data 是一个函数

Vue [Day4],vue.js,前端
components/BaseButton.vue

<template>
    <div class="BaseButton">
        <button @click="count--">-</button>
        <span>{{ count }}</span>
        <button @click="count++">+</button>
    </div>
</template>

<script>
export default {
    // data必须写成函数,不能是对象
    data() {
        return {
            count: 999
        }
    }
}
</script>

<style>
</style>


App.vue

<template>
    <div id="app">
        <BaseButton></BaseButton>
        <BaseButton></BaseButton>
        <BaseButton></BaseButton>
    </div>
</template>

<script>
import BaseButton from './components/BaseButton.vue'

export default {
    name: 'App',
    components: {
        BaseButton
    }
}
</script>

<style>
</style>

组件通信

Vue [Day4],vue.js,前端


Vue [Day4],vue.js,前端



父 -> 子 props

Vue [Day4],vue.js,前端
components/SonTest.vue

<template>
    <div class="son">
        {{ title }}
        <!-- 渲染使用 -->
    </div>
</template>

<script>
export default {
    // 2.通过props进行接受
    // 这里的名字必须和App.vue里的<Son :title="MyTitle"></Son> 相同
    props: ['title']
}
</script>

<style  scoped>
div {
    border: 1px solid black;
    width: 100px;
    height: 100px;
}
</style>


App.vue

<template>
    <div id="app">
        我是爸爸
        <!-- 1.给组件标签,添加属性的方式,传值 -->
        <SonTest :title="MyTitle"></SonTest>
    </div>
</template>

<script>
import SonTest from './components/SonTest.vue'

export default {
    components: {
        SonTest
    },
    data() {
        return {
            MyTitle: 'slxhhhh'
        }
    }
}
</script>

<style  >
div {
    border: 1px solid black;
    width: 300px;
    height: 200px;
}
</style>



prop概念

Vue [Day4],vue.js,前端components/UserInfo.vue

<template>
    <div class="UserInfo">
        <h1>个人信息</h1>
        <h3>姓名{{ username }}</h3>
        <h3>年龄{{ age }}</h3>
        <h3>是否单身{{ isSingle }}</h3>
        <h3>座驾{{ car.brand }}</h3>
        <h3>兴趣爱好{{ hobby.join('、') }}</h3>
    </div>
</template>

<script>
export default {
    props: ['username', 'age', 'isSingle', 'car', 'hobby']
}
</script>

<style>
</style>

App.vue

<template>
    <div id="app">
        <UserInfo
            :username="username"
            :age="age"
            :isSingle="isSingle"
            :car="car"
            :hobby="hobby"
        ></UserInfo>
    </div>
</template>

<script>
import UserInfo from './components/UserInfo.vue'

export default {
    components: {
        UserInfo
    },
    data() {
        return {
            username: 'slx',
            age: 20,
            isSingle: true,
            car: {
                brand: 'affrf'
            },
            hobby: ['aaaa', 'cccc', 'bbbb']
        }
    }
}
</script>

<style  >
div {
    border: 1px solid black;
    width: 300px;
    height: 400px;
}
</style>





props校验
类型校验 基础写法+完整写法

Vue [Day4],vue.js,前端
components/BaseProgress.vue

<template>
    <div class="BaseProgress">
        <div class="progress">
            <!-- 在这里面width  不用加{{}}    并且{}里面 是js对象  ,所以要遵守驼峰命名法 也就是 background-color 要变成 backgroundColor-->
            <div
                class="inner"
                :class="{
                    low: w < 50,
                    high: w > 70,
                    over: w == 100
                }"
                :style="{ width: w + '%' }"
            >
                <span>{{ w }}%</span>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    // 没有校验
    // props: ['w']

    // 1.基础校验
    // props: {
    //     // 校验的属性名:类型  Number、String Boolean
    //     w: Number
    // }

    // 2.完整写法(类型、非空、默认、自定义校验
    props: {
        w: {
            // 写成对象形式
            type: Number,
            // required: true,
            default: 10,
            validator(value) {
                // return false
                console.log(value)

                if (value >= 0 && value <= 100) {
                    return true
                }
                console.log('传入的值要是0~100')
                return false
            }
        }
    }
}
</script>

<style scoped>
.BaseProgress {
    margin: 10px;
}

.progress {
    width: 300px;
    height: 40px;
    margin-bottom: 40px;
    background-color: #cdf92c;
    border-radius: 25px;
    padding: 5px;
}

.inner {
    background-color: #0df6c7;
    border-radius: 25px;
    height: 35px;
    margin-top: 3px;
    /* width: 20%; */
}

.low {
    background-color: #92ee61;
}

.high {
    background-color: rgb(141, 179, 216);
}

.over {
    background-color: rgb(0, 128, 255);
}

.inner span {
    width: 100%;
    text-align: right;
    display: block;
    line-height: 90px;
}
</style>

App.vue
<template>
    <div id="app">
        <!-- 没传值,就用默认的10 -->
        <BaseProgress></BaseProgress>

        <BaseProgress :w="width"></BaseProgress>
    </div>
</template>

<script>
import BaseProgress from './components/BaseProgress.vue'

export default {
    components: {
        BaseProgress
    },
    data() {
        return {
            // width: 'sfsd'
            width: 20
        }
    }
}
</script>

<style  >
</style>

prop & data 、单向数据流

Vue [Day4],vue.js,前端components/BaseProgress.vue

<template>
    <div class="BaseProgress">
        <div class="progress">
            <!-- 在这里面width  不用加{{}}    并且{}里面 是js对象  ,所以要遵守驼峰命名法 也就是 background-color 要变成 backgroundColor-->
            <div
                class="inner"
                :class="{
                    low: w < 50,
                    high: w > 70,
                    over: w == 100
                }"
                :style="{ width: w + '%' }"
            >
                <span>{{ w }}%</span>
            </div>
        </div>

        <button @click="handleFn(75)">设置75%</button>
        <button @click="handleFn(100)">设置100%</button>
        <!-- props传过来的数据(外部数据),不能直接改 -->
    </div>
</template>

<script>
export default {
    props: {
        w: {
            // 写成对象形式
            type: Number,
            // required: true,
            default: 10,
            validator(value) {
                if (value >= 0 && value <= 100) {
                    return true
                }
                console.log('传入的值要是0~100')
                return false
            }
        }
    },
    methods: {
        handleFn(tt) {
            this.$emit('changeWidth', tt)
        }
    }
    // 父组件的props更新,会单向向下流动,影响到子组件
}
</script>

<style scoped>
.BaseProgress {
    margin: 10px;
}

.progress {
    width: 300px;
    height: 40px;
    margin-bottom: 40px;
    background-color: #cdf92c;
    border-radius: 25px;
    padding: 5px;
}

.inner {
    background-color: #0df6c7;
    border-radius: 25px;
    height: 35px;
    margin-top: 3px;

    /* width: 20%; */
}

.low {
    background-color: #92ee61;
}

.high {
    background-color: rgb(141, 179, 216);
}

.over {
    background-color: rgb(0, 128, 255);
}

.inner span {
    width: 100%;
    text-align: right;
    display: block;
    line-height: 90px;
}
</style>


App.vue

<template>
    <div id="app">
        <!-- 没传值,就用默认的10 -->
        <!-- <BaseProgress></BaseProgress> -->

        <BaseProgress :w="width" @changeWidth="changeFn"></BaseProgress>
    </div>
</template>

<script>
import BaseProgress from './components/BaseProgress.vue'

export default {
    components: {
        BaseProgress
    },
    data() {
        return {
            // width: 'sfsd'
            width: 20
        }
    },
    methods: {
        changeFn(tt) {
            this.width = tt
        }
    }
}
</script>

<style  >
</style>






子 -> 父 $emit

Vue [Day4],vue.js,前端
components/Son.vue

<template>
  <div class="son" style="border: 3px solid #000; margin: 10px">
    我是Son组件 {{ title }}
    <button @click="changeFn">修改title</button>
  </div>
</template>

<script>
export default {
  name: 'Son-Child',
  props: ['title'],
  methods: {
    changeFn() {
      // 通过this.$emit() 向父组件发送通知
      this.$emit('changTitle','传智教育')
    },
  },
}
</script>

<style>
</style>

App.vue


<template>
  <div class="app" style="border: 3px solid #000; margin: 10px">
    我是APP组件
    <!-- 2.父组件对子组件的消息进行监听 -->
    <Son :title="myTitle" @changTitle="handleChange"></Son>
  </div>
</template>

<script>
import Son from './components/Son.vue'
export default {
  name: 'App',
  data() {
    return {
      myTitle: '学前端,就来黑马程序员',
    }
  },
  components: {
    Son,
  },
  methods: {
    // 3.提供处理函数,提供逻辑
    handleChange(newTitle) {
    //这里的newTitle就是子组建  this.$emit('changTitle','传智教育')  传来的'传智教育'
      this.myTitle = newTitle
    },
  },
}
</script>

<style>
</style>

通过后面的启发,父组件还可以直接@事件名=" 父数据 = $event "
Vue [Day4],vue.js,前端


当然,组件间也可以传递响应式数据
Son.vue

<template>
    <div class="son" style="border: 3px solid #000; margin: 10px">
      我是Son组件 title:[{{ title }}]
      <input  v-model="txt" type="text">
      <button @click="changeFn">修改title</button>
    </div>
  </template>
  
  <script>
  export default {
    name: 'Son-Child',
    props: ['title'],
    data(){
        return {
            txt:''
        }
    },
    methods: {
      changeFn() {
        // 通过this.$emit() 向父组件发送通知
        this.$emit('changTitle',this.txt)
      },
    },
  }
  </script>
  
  <style>
  </style>
  

App.vue


<template>
    <div class="app" style="border: 3px solid #000; margin: 10px">
      我是APP组件
      <!-- 2.父组件对子组件的消息进行监听 -->
      <Son :title="myTitle" @changTitle="myTitle = $event"></Son>
    </div>
  </template>
  
  <script>
  import Son from './components/Son.vue'
  export default {
    name: 'App',
    data() {
      return {
        myTitle: '学前端,就来黑马程序员',
      }
    },
    components: {
      Son,
    },
    methods: {
      // 3.提供处理函数,提供逻辑
    //   handleChange(newTitle) {
    //     console.log(newTitle);
        
    //     this.myTitle = newTitle
    //   },
    },
  }
  </script>
  
  <style>
  </style>
  

Vue [Day4],vue.js,前端Vue [Day4],vue.js,前端



非父子通信 event bus事件总线

Vue [Day4],vue.js,前端components/BaseA.vue

<template>
    <div class="A">
        我是A组件(接收方)
        <p>{{ msg }}</p>
    </div>
</template>

<script>
import Bus from '../utils/EventBus'
export default {
    created() {
        // 2.在A组件(接受方)监听Bus的事件(订阅消息)
        // 事件名,回调
        Bus.$on('sendMsg', (msg) => {
            console.log(msg)
            this.msg = msg
        })
    },
    data() {
        return {
            msg: ''
        }
    }
}
</script>

<style>
.A {
    width: 200px;
    height: 100px;
    border: 1px solid black;
}
</style>

在这里,msg就是发送方BaseB的恐龙扛狼


components/BaseB.vue

<template>
    <div class="B">
        我是B组件(发布方)
        <button @click="clickSend">发布通知</button>
    </div>
</template>

<script>
import Bus from '../utils/EventBus'
export default {
    methods: {
        clickSend() {
            // 3.B组件(发送方)触发事件的方式传递参数(发布消息)
            Bus.$emit('sendMsg', '恐龙扛狼') // Bus.$on('sendMsg', (msg) => {})和这里的名字同名
        }
    }
}
</script>

<style>
.B {
    width: 200px;
    height: 100px;
    border: 1px solid black;
}
</style>


App.vue

<template>
    <div id="app">
        <BaseA></BaseA>
        <BaseB></BaseB>
    </div>
</template>

<script>


import BaseA from './components/BaseA.vue'
import BaseB from './components/BaseB.vue'
export default {
    components: {
        BaseA,
        BaseB
    }
}
</script>

<style>
</style>


utils/EventBus.js
utils通常用来放工具

// 创建一个都能访问到的事件总线(空的Vue实例)
import Vue from 'vue'

const Bus = new Vue()

export default Bus


非父子通信——provide & inject(扩展)

Vue [Day4],vue.js,前端


总结

Vue [Day4],vue.js,前端



【综合案例】——小黑记事本— 组件版

Vue [Day4],vue.js,前端

components/TodoHeader.vue

<template>
    <div class="head">
        <h1>小黑记事本</h1>
        <input
            @keyup.enter="handleAdd"
            v-model="todoName"
            type="text"
            placeholder="请输入待办事项"
        />
        <button @click="handleAdd">添加任务</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            todoName: ''
        }
    },
    methods: {
        handleAdd() {
            if (this.todoName.trim() == '') {
                // 输入许多的空格,无效输入,不让添加
                alert('请输入内容')
                return
            }

            this.$emit('add', this.todoName)

            // 点击添加之后,输入框清空
            this.todoName = ''
        }
    }
}
</script>

<style>
.head {
    width: 243px;
    /* background-color: #584949; */
}

input {
    height: 30px;
    vertical-align: middle;
}

.head button {
    height: 30px;
}
</style>


components/TodoMain.vue

<template>
    <section class="body">
        <ul>
            <li v-for="(item, index) in todoList" :key="item.id">
                <span>{{ index + 1 }}</span>
                <span class="content">{{ item.name }}</span>
                <button @click="handleDel(item.id)">×</button>
            </li>
        </ul>
    </section>
</template>

<script>
export default {
    props: {
        todoList: Array
    },
    methods: {
        handleDel(tt) {
            this.$emit('del', tt)
        }
    }
}
</script>

<style>
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    list-style: none;
}
.body li {
    width: 234px;
    height: 50px;
    display: flex;
    line-height: 50px;
    /* justify-content: space-between; */
    background-color: #de8282;
    border-bottom: black solid 2px;
}

.body li .content {
    flex: 1;
}

.body li button {
    height: 50%;
    align-self: center;
    display: none;
}

.body li:hover button {
    display: block;
    width: 20px;
}
</style>


components/TodoFooter.vue

<template>
    <div v-show="todoList.length > 0" class="footer">
        <span
            >合计:<strong>{{ todoList.length }}</strong></span
        >
        <button @click="clear()">清空任务</button>
    </div>
</template>

<script>
export default {
    props: {
        todoList: Array
    },
    methods: {
        clear() {
            this.$emit('clear')
        }
    }
}
</script>

<style>
.footer {
    width: 234px;
    display: flex;
    justify-content: space-between;
}
</style>


components/App.vue

<template>
    <div id="app">
        <TodoHeader @add="handleAdd"></TodoHeader>
        <TodoMain :todoList="todoList" @del="handleDel"></TodoMain>
        <TodoFooter @clear="handleClear" :todoList="todoList"></TodoFooter>
    </div>
</template>

<script>
import TodoHeader from './components/TodoHeader.vue'
import TodoMain from './components/TodoMain.vue'
import TodoFooter from './components/TodoFooter.vue'
export default {
    components: {
        TodoHeader,
        TodoMain,
        TodoFooter
    },

    // 渲染功能:
    // 1.提供数据:写在公共的父组件 App.vue
    // 2.通过父组件,将数据传递给TodoMain
    // 3.利用v-for 渲染

    // 添加功能
    // 1.收集表单数据 v-model
    // 2.监听事件(回车+点击 都要添加
    // 3.子传父 将任务名称传给父App.vue
    // 4.进行添加 unshift(自己的数据,自己负责)

    // 删除功能
    // 1.监听事件(删除的点击) 携带id
    // 2.子传父,将删除的id传给父组件App.vue
    // 3.父组件删除 filter(自己的数据,自己负责)

    // 底部合计:父传子list  渲染
    // 清空功能:子传父,通知到父组件 父组件清空
    // 持久化存储:watch深度监视->  往本地存 -> 进入页面优先读取本地
    data() {
        return {
            todoList: JSON.parse(localStorage.getItem('list')) || [
                { id: 1, name: '吃水果' },
                { id: 2, name: '喝酸奶' }
            ]
        }
    },
    methods: {
        handleAdd(todoName) {
            this.todoList.unshift({
                id: +new Date(),
                name: todoName
            })
        },
        handleDel(tt) {
            this.todoList = this.todoList.filter((item) => item.id != tt)
        },
        handleClear() {
            this.todoList = []
        }
    },
    watch: {
        todoList: {
            deep: true,
            handler(newValue) {
                localStorage.setItem('list', JSON.stringify(newValue))
            }
        }
    }
}
</script>

<style  >
#app {
    /* width: 234px;
    height: 200px;
    display: flex;
    flex-direction: column; */

    margin: 50px 50px;
}
</style>





v-model原理

$event
Vue [Day4],vue.js,前端 解释一下
用上一个小黑记事本为例
<TodoMain :todoList=“todoList” @del=“handleDel”>
所以说 :value 是父传子
@input 是子传父
所以才能实现双向绑定



$evevnt也就是e
如果应用于复选框,就是check属性,和change事件的合写

表单类组件封装

e.target.value
也就是 在html里面,就写成$event ; 在js里面,就写成e.target.value
Vue [Day4],vue.js,前端components/BaseSelect.vue
子组件不可以用v-model,但是父组件是非常可以用的,因为是自己的数据自己负责

<template>
    <div class="BaseSelect">
        <!-- <select v-model="cityId">
        这样写是不行的,因为父组件的数据,只能父组件改,
        而v-model是双向的,他在尝试更改父亲的数据,他要造反,要谋权篡位,所以报错了  
        -->

        <!-- 
            :value="cityId"   用来父传子
        @change="handleChange" 用来子传父
        -->
        <select :value="cityId" @change="handleChange">
            <option value="101">北京</option>
            <option value="102">深圳</option>
            <option value="103">上海</option>
            <option value="104">广州</option>
            <option value="105">辽宁</option>
            <option value="106">福建</option>
        </select>
    </div>
</template>

<script>
export default {
    props: {
        cityId: String
    },
    methods: {
        handleChange(e) {
            console.log(e.target.value)
            this.$emit('changeId', e.target.value)
        }
    }
}
</script>

<style>
</style>



App.vue

<<template>
    <!-- :cityId="selectId"  用来父传子
       @changeId="selectId = $event"   用来子传父
    
    -->
    <BaseSelect :cityId="selectId" @changeId="selectId = $event"></BaseSelect>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
    components: {
        BaseSelect
    },
    data() {
        return {
            selectId: '106'
        }
    }
}
</script>

<style>
</style>



@changeId="selectId = $event " 中的$event是什么

在Vue中,$event是一个特殊的变量,用于在事件处理函数中访问触发事件时传递的数据。它代表了事件对象,包含了与事件相关的信息。

在你提供的代码中,@changeId="selectId = $event"表示当 BaseSelect 组件触发 changeId 事件时,将事件对象中的数据赋值给 selectId。

具体来说,$event 是一个占位符,用于接收传递给事件处理函数的参数。在这个例子中,BaseSelect 组件在触发 changeId 事件时,会将选中的城市ID作为参数传递给事件处理函数。然后,通过 $event 来访问这个参数,并将其赋值给 selectId。

例如,如果 BaseSelect 组件在触发 changeId 事件时传递了一个值为 123 的参数,那么 selectId 将被赋值为 123。代码示例中的 @changeId=“selectId = $event” 就是将事件对象中的数据赋值给 selectId 的方式。

请注意,$event 只是一个约定俗成的命名,你也可以使用其他变量名来接收事件对象中的数据。例如,你可以使用 @changeId=“selectId = value”,其中 value 是你自己定义的变量名,它将接收事件对象中的数据。

总之,$event 是Vue中的一个特殊变量,用于在事件处理函数中访问事件对象中传递的数据。它可以帮助你在事件处理函数中获取和处理事件的相关信息。

v-model 简化代码

注意是父组件使用v-model,不是子组件
子组建中只能用value接受???
下拉框是@change事件
Vue [Day4],vue.js,前端components/BaseSelect.vue

<template>
    <div class="BaseSelect">
        <!-- :value="value"  父传子 -->
        <select :value="value" @change="handleChange">
            <option value="101">北京</option>
            <option value="102">深圳</option>
            <option value="103">上海</option>
            <option value="104">广州</option>
            <option value="105">辽宁</option>
            <option value="106">福建</option>
        </select>
    </div>
</template>

<script>
export default {
    // 父传子
    props: {
        value: String
    },
    methods: {
        // 子传父
        // 监听
        handleChange(e) {
            console.log(e.target.value)
            this.$emit('input', e.target.value)
        }
    }
}
</script>

<style>
</style>


App.vue

<template>
    <!-- v-model => :value(父传子)  + @input  子传父 -->
    <BaseSelect v-model="selectId"></BaseSelect>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
    components: {
        BaseSelect
    },
    data() {
        return {
            selectId: '106'
        }
    }
}
</script>

<style>
</style>


Vue [Day4],vue.js,前端



Vue [Day4],vue.js,前端




发现父组件的 :属性名@事件名都是可以自己命名的,但是子组建的不行
Vue [Day4],vue.js,前端

小结

Vue [Day4],vue.js,前端


封装输入框组件

Vue [Day4],vue.js,前端


Vue [Day4],vue.js,前端



components/BaseInput.vue

<template>
    <div class="BaseInput">
     <!-- 
    			 这里使用@change 和 @input 事件的效果是不一样的 
            前者 输入框失去焦点时触发
            后者 输入框内容发生改变时就会触发
        -->
        <input @change="handleChange" :value="value" type="text" />
    </div>
</template>

<script>
export default {
    props: {
        value: String
    },
    methods: {
        handleChange(e) {
            console.log(e.target.value)

            this.$emit('input', e.target.value)
        }
    }
}
</script>

<style>
</style>


App.vue

<template>
    <div class="app">
    			父组件显示text:  {{ text }}
        <BaseInput v-model="text"></BaseInput>
    </div>
</template>

<script>
import BaseInput from './components/BaseInput.vue'
export default {
    components: {
        BaseInput
    },
    data() {
        return {
            text: 'slx'
        }
    }
}
</script>

<style>
</style>



.sync修饰符 (父子双向绑定

所以就还是父组件简单了点,子组件还是老样子
Vue [Day4],vue.js,前端在书写上比较比v-model麻烦,所以,封装表单还是v-model,其余的用.sync较好


components/SB.vue
发现这里的update:visable 可以改成其他名字,这个:有必要加吗,还是就是起了这个名字??

<template>
    <div v-show="visable" class="base-dialog-wrap">
        <div class="base-dialog">
            <div class="title">
                <h3>温馨提示:</h3>
                <button @click="close" class="close">x</button>
            </div>
            <div class="content">
                <p>你确认要退出本系统么?</p>
            </div>
            <div class="footer">
                <button @click="close">确认</button>
                <button @click="close">取消</button>
            </div>
        </div>
    </div>
</template>
  
  <script>
export default {
    props: {
        visable: Boolean
    },
    methods: {
        close() {
            this.$emit('update:visable', false)
        }
    }
}
</script>
  
  <style scoped>
.base-dialog-wrap {
    width: 300px;
    height: 200px;
    box-shadow: 2px 2px 2px 2px #ccc;
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 0 10px;
    z-index: 9;
    background-color: #fff;
}
.base-dialog .title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 2px solid #000;
}
.base-dialog .content {
    margin-top: 38px;
}
.base-dialog .title .close {
    width: 20px;
    height: 20px;
    cursor: pointer;
    line-height: 10px;
}
.footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 26px;
}
.footer button {
    width: 80px;
    height: 40px;
}
.footer button:nth-child(1) {
    margin-right: 10px;
    cursor: pointer;
}
</style>


App.vue

<template>
    <div class="app">
        <button @click="isShow = true">退出按钮</button>
        <div :class="{ show_bg: isShow }">
            <SB :visable.sync="isShow"></SB>
            <!-- :visable.sync => :visable + @update:visable -->
        </div>
    </div>
</template>
  
  <script>
import SB from './components/SB.vue'
export default {
    data() {
        return {
            isShow: false
        }
    },
    methods: {},
    components: {
        SB
    }
}
</script>
  
<style>
.show_bg {
    position: absolute;
    top: 0;
    z-index: 2;
    width: 100%;
    height: 100%;
    background-color: #c4bbbba4;
}
</style>



ref 和 $refs (获取当前组件内的dom元素

Vue [Day4],vue.js,前端

获取dom元素

<div ref="mychart" class="BaseEchart"></div>
 var myChart = echarts.init(this.$refs.mychart)

components/BaseEchart.vue

<template>
    <div ref="mychart" class="BaseEchart"></div>
</template>

<script>
import * as echarts from 'echarts'
export default {
    mounted() {
        // var myChart = echarts.init(document.querySelector('.BaseEchart'))
        var myChart = echarts.init(this.$refs.mychart)
        var option = {
            xAxis: {
                type: 'category',
                data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
            },
            yAxis: {
                type: 'value'
            },
            series: [
                {
                    data: [120, 200, 150, 80, 70, 110, 130],
                    type: 'bar'
                }
            ]
        }

        option && myChart.setOption(option)
    }
}
</script>

<!-- <style scoped> -->
<style >
.BaseEchart {
    width: 500px;
    height: 500px;
}
</style>


App.vue

<template>
    <div class="app">
        <div class="BaseEchart">捣乱的div</div>
        <BaseEchart></BaseEchart>
    </div>
</template>

<script>
import BaseEchart from './components/BaseEchart.vue'

export default {
    components: {
        BaseEchart
    }
}
</script>

<style  >
</style>


获取组件实例

Vue [Day4],vue.js,前端
componentes/BaseForm.vue

<template>
    <div class="BaseForm">
        用户名: <input v-model="username" type="text" /><br />
        密码: <input v-model="password" type="text" /><br />
    </div>
</template>

<script>
export default {
    data() {
        return {
            username: '',
            password: ''
        }
    },
    methods: {
        getValues() {
            return {
                username: this.username,
                psd: this.password
            }
        },
        clearValues() {
            this.username = ''
            this.password = ''
        }
    }
}
</script>

<style>
</style>


App.vue

<template>
    <div class="app">
        <BaseForm ref="Form"></BaseForm>
        <button @click="getDate">获取数据</button>
        <button @click="clearDate">清空数据</button>
    </div>
</template>

<script>
import BaseForm from './components/BaseForm.vue'
export default {
    components: {
        BaseForm
    },
    methods: {
        getDate() {
            console.log('www')

            console.log(this.$refs.Form.getValues())
        },
        clearDate() {
            this.$refs.Form.clearValues()
        }
    }
}
</script>

<style>
</style>


this.$refs['aa']

在项目里看到了另一种写法,之前没学过这种,记录一下
this.$refs['aa']this.$refs.aa 这两种写法在大多数情况下是等效的,可以互相替换使用。

在 Vue 组件中,$refs 是一个对象,它包含了通过 ref 属性引用的子组件或 DOM 元素。当你在模板中使用 ref 属性给元素或组件命名时,可以使用 $refs 来访问这些引用。

通常情况下,你可以使用点 . 运算符来访问 $refs 中的引用,例如 this.$refs.aa。这种写法更简洁直观,与访问对象属性的方式相似。

this.$refs['aa'] 使用方括号 [] 来访问 $refs 中的引用。这种写法可以动态地根据变量的值来访问引用,例如 this.$refs[refName],其中 refName 是一个变量。

所以,如果你的引用名称是一个静态的字符串,那么 this.$refs['aa']this.$refs.aa 是等效的,可以互相替换使用。

需要注意的是,当引用名称包含特殊字符或变量时,使用方括号 [] 的写法更适用。例如,this.$refs['my-component-' + index] 可以动态地根据索引值来访问不同的引用。

总结起来,this.$refs['aa']this.$refs.aa 这两种写法在大多数情况下是相同的,可以互相替换使用。选择哪种写法取决于你的需求和引用名称的特殊性。



Vue 异步更新、$nextTick

Vue [Day4],vue.js,前端
App.vue

<template>
    <div class="app">
        <div v-if="isEdit">
            <input ref="inp" v-model="editValue" type="text" />
            <button @click="over">ok</button>
        </div>
        <div v-else>
            {{ title }}
            <button @click="changeTitle">edit</button>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            editValue: '',
            title: '我是title',
            isEdit: false
        }
    },
    methods: {
        changeTitle() {
            // 1.显示输入框(异步dom更新
            this.isEdit = true

            // 2.让输入框获取焦点
            // $nextTick等dom更新完,立刻执行函数体
            this.$nextTick(() => {
                this.$refs.inp.focus()
            })
        },
        over() {
            this.title = this.editValue
            this.isEdit = false
        }
    }
}
</script>

<style>
</style>

这个光标异步的问题 在Day5中也有解决方法——自定义指令文章来源地址https://www.toymoban.com/news/detail-631736.html

到了这里,关于Vue [Day4]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端学习——ajax (Day4)

    Promise - 链式调用

    2024年02月16日
    浏览(27)
  • day4:Node.js 核心库

    常用工具模块 Node.js有许多常用的工具,以下是一些常见的: util : 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心 JavaScript 的功能 过于精简的不足。 Lodash :Lodash是一个功能丰富的JavaScript实用工具库,提供了许多用于处理数组、对象和其他常见数据结构的方法

    2024年02月07日
    浏览(35)
  • 【Node.js学习 day4——模块化】

    什么是模块化与模块? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化 其中拆分的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用。 什么是模块化项目? 编码时是按照模块一个一个编码的

    2024年01月16日
    浏览(41)
  • 前端Vue入门-day01-初识vue与vue指令

    -(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 Vue 快速上手 Vue 概念 创建实例   插值表达式 响应式特性 开发者工具  Vue 指令  v-show  v-if  v-else  v-else-if  v-on v-bind  v-for key  v-model  概念:Vue 是一个用于 构建用户

    2024年02月09日
    浏览(37)
  • 前端Vue入门-day02

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 指令补充 指令修饰符 v-bind 对于样式控制的增强  操作class 案例:京东秒杀 tab 导航高亮 操作style  v-model 应用于其他表单元素  computed 计算属性 基础语法 computed 计算属

    2024年02月13日
    浏览(38)
  • 前端Vue入门-day04-用vue实现组件通信

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 组件的三大组成部分 注意点说明 组件的样式冲突 scoped data 是一个函数 组件通信 什么是组件通信 不同的组件关系 和 组件通信方案分类   父子通信流程图:  父 → 子

    2024年02月15日
    浏览(40)
  • 前端Vue入门-day06-路由进阶

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 路由的封装抽离 声明式导航 导航链接  两个类名  自定义高亮类名  跳转传参 1. 查询参数传参 2. 动态路由传参 两种传参方式的区别  Vue路由  重定向 404 编程式导航

    2024年02月14日
    浏览(32)
  • 前端Vue入门-day07-Vuex入门

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 自定义创建项目 vuex概述 构建 vuex [多组件数据共享] 环境  创建一个空仓库 state 状态 1. 提供数据: 2. 使用数据: mutations  辅助函数 - mapMutations actions 辅助函数 - mapAc

    2024年02月14日
    浏览(30)
  • 前端Vue入门-day03-用Vue实现工程化、组件化开发

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 生命周期 Vue 生命周期 和 生命周期的四个阶段  Vue 生命周期函数(钩子函数) 案例-create的应用 案例-mounted的应用 工程化开发 脚手架 Vue CLI 开发 Vue 的两种方式 基本介

    2024年02月15日
    浏览(38)
  • 前端Vue入门-day08-vant组件库

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 vant 组件库  安装  导入 全部导入 按需导入 浏览器配饰 Viewport 布局 Rem 布局适配  目标:认识第三方 Vue组件库 vant-ui 组件库:第三方 封装 好了很多很多的 组件 ,整合

    2024年02月14日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包