Vue之组件

Vue之组件

vue的核心就是组件的使用,玩好了组件才能将前面的基础更好的运用起来。

组件使我们的项目解耦,更加符合vue的设计思想MVVM。

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

例如,你可能会有页头,侧边栏,内容区等组件,每个组件又包含了其它的像导航栏链接、博文之类的组件

组件的创建

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>组件</title>
</head>
<body>
<div id="app"></div>

<script src="vue.js"></script>
<script>
    // Vheader是组件名,最好大写开头
    Vue.component('Vheader', {
// 和实例对象不一样,这里data不再返回对象,必须要是个函数,而且必须return data:
function () { return { // 必须要return,哪怕是空对象 } }, template: `<div class="header"> <div class="w"> <div class="w1"> <img src="./logo.png"> </div> <div class="w-r"> <button>登陆</button><button>注册</button> </div> </div> </div>` }); var app = new Vue({ el: '#app', data: {}, computed: {}, methods: {} }) </script> </body> </html>

组件的使用

组件是可服用的Vue实例,并且带有一个名字,这个例子中是<Vheader> 。

我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

<div id="app">
    <Vheader></Vheader>
</div>

组件的复用

<div id="app">
    <Vheader></Vheader>
    <Vheader></Vheader>
    <Vheader></Vheader>
</div>

vue-cli脚手架安装和webpack-simple模板项目生成

vue-cli是一个官方发布vue.js项目脚手架,使用vue-cli可以快速创建vue项目。

安装nodejs

官网下载安装  

node -v检查是否安装成功

npm  是 nodejs package manager ,跟python的pip java mvn一样

安装vue-cli

安装好node之后,我们就可以直接全局安装vue-cli:

npm install -g vue-cli

安装慢的话用淘宝镜像,百度淘宝镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org

如果安装失败使用npm cache clean清理缓存,然后再重新安装。

安装完成后vue -V查看vue版本。 

vue hlep查看可用命令

vue list查看官方提供的模板

安装webpack-simple模板

初始化项目,加项目名myProject就创建一个项目名的目录里生成,不加名字默认再当前目录生成项目

vue init webpack-simple myProject

 

最后一步选N,sass是vue的预处理语言还不会。

然后它就告诉你要继续干什么:

webpack + nodejs 使我们更方便的开发,热重载。

使用的webpack模板

打开项目myProject,映入眼帘的是一个也看不懂。。。

等等..main.js:

import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app',
  render: h => h(App)
})

可以看出,这个和django的manage.py文件一样都是一个入口文件。

入口文件引的第一个文件就是App.vue:

看看人家是怎么设计的:

<!--一个组件有三部分组成-->
<!-- 一个页面就把三个部分全部包含了 -->
<template>
    <!--第一部分,页面的结构-->    
    <!-- 注意template下整个必须是一个闭合标签,因为他是一个大组件包裹一个个小组件 -->
    <!-- 比如把下面的注释去掉就会报错 -->
    <!-- <div class="app2"></div> -->
    <div class="app">
        <h3>{{ msg }}</h3>
        <p>heihei</p>
    </div>
</template>
<script>
    // 第二部分,页面的业务逻辑
    export default {
        name:'App',          // 只是个名字
        data(){              // 数据属性必须是个函数
            return {
                msg:'组件'
            }
        },
        methods: {

        },
        computed: {

        }
    }
</script>
<style>
    /*第三部分,css样式*/
</style>

解耦组件

上面的是一个大组件,要解耦成一个个小组件,所以我们要创建一个存放一个个小组件的文件加。

src下面新建一个folder,就叫components。

并新建三个文件:

每个文件里的结构,跟App.vue里的一样。

<template>
    <header class="nav">  <!--footer的class:foot,content:wrap-->
        我是header
    </header>
</template>
<script>
    export default {
        name:'Vheader',// footer:Vfooter,content:content     
        data(){             
            return {

            }
        },
    }
</script>
<style scoped>  //scoped:组件里的样式只在自己的组件里生效
</style>

引入子组件

接下来这些小组件怎么在大组件里用呢:

<template>
    <div class="app">
        <h3>{{ msg }}</h3>
        <p>heihei</p>
        <Vcontent></Vcontent>
        <Vcontent></Vcontent>
        <Vcontent></Vcontent>
    </div>

</template>
<script>
// 1. 先引入子组件
import Vcontent from './components/Vcontent.vue'
import Vheader from './components/Vheader.vue'
import Vfooter from './components/Vfooter.vue'
    export default {
        name:'App',      
        data(){              
            return {
                msg:'组件'
            }
        },
        methods: {

        },
        computed: {

        },
        // 2. 挂载组件
        components:{
            Vheader,   // 相当于Vheader:Vheader,key和value相同可以简写
            Vcontent,
            Vfooter,
        }
    }
</script>
<style>
</style>

组件间传值

父组件向子组件传递数据,通过Prop


1. 父组件向子组件传值第一步就是, 绑定自定义的属性,在导入的子组件标签: <Vheader :title = '父组件中data声明的数据属性'/>
2. 父子传值的第二步就是,要通过props验证,再子组件里写这个方法
// 数组类型就必须写Array,写Str就会报错,对应类型可以查官网,然后就可以在子组件里用这个数据量了 props:{ cityArray:Array, }

type 可以是下列原生构造函数中的一个:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol

子组件传递数据到父组件,通过自定义事件

1. 子父组件传值,第一步就是自定义事件
<Vcontent v-on:addCunHandler = 'addHandler'></Vcontent>
2. 给子组件中的某个按钮绑定原生事件,我们可以调用内建的 this.$emit('自定义的事件名','传递的数据'),来向父级组件触发一个自定义的事件.
        methods:{
            addCunHandler(){
                // 通过$emit触发自定义事件
                // 参数1:自定义事件的名字
                // 参数2:数据
                this.$emit('addCunHandler','北海北');
            }
        },
 

MarkDown项目

写一个markdown项目,练习一下组件传值

父组件:App.vue

<template>
    <div class="app">
        <Vheader></Vheader>
        <h2>{{ currentMsg }}</h2>
        <!-- webpack里的file-loader工具能把图片看做变量 -->
        <!-- 所以取图片用下面这种方式即可 -->
        <img :src="imgSrc">
        <ul>
            <li v-for = 'item in getArray'>
                <!-- a标签里的href="javascript;"表示阻止a标签的事件,等于a标签失效了 -->
                <a href="javascript;">{{item}}</a>
            </li>
        </ul>
        <!-- 来个点击事件 -->
        <button @click='clickHandler'>修改</button>
        
        <!-- 子父组件传值,第一步就是自定义事件 -->
        <Vcontent v-on:addCunHandler = 'addHandler'></Vcontent>
        <!-- 父子组件传值,第一步就是绑定自定义属性 -->
        <Vfooter :cityArray = 'citys'></Vfooter>
    </div>
</template>
<script>
    import imgSrc from './assets/logo.png'
    // 子组件渲染到父组件的第一步就是,导入
    import Vheader from './components/Vheader.vue'
    import Vcontent from './components/Vcontent.vue'
    import Vfooter from './components/Vfooter.vue'
    export default {
        name:'App',     
        data(){             
            return {
                msg:'hello world',
                stars:[
                    "nsn","alex",'nezha'
                ],
                imgSrc:imgSrc,
                citys:['沙河','通州','西二旗']
            }
        },
        methods: {
            clickHandler(){
                this.msg = '哈哈哈',
                this.stars.push('anglebaby')
            },
            addHandler(str){
                this.citys.push(str)
            }
        },
        // 所有的属性,都可以被计算属性绑定起来,多用计算属性
        computed: {
            currentMsg(){
                return this.msg;
            },
            getArray(){
                return this.stars
            }
        },
        // 子组件渲染到父组件的第二步就是,挂载
        components:{
            Vheader,
            Vfooter,
            Vcontent
        }
    }
</script>
<style>
*{
    padding: 0px;
    margin: 0px;
}
</style>

子组件Vfooter

<template>
    <footer class="foot"> 
        <ul v-for = 'item in cityArray'>
            <li>{{item}}</li>
        </ul>
    </footer>
</template>
<script>
    export default {
        name:'Vfooter', 
        data(){             
            return {

            }
        },
        // 父子传值的第二步就是,一定要通过props验证
        // 数组类型就必须写Array,写Str就会报错,对应类型可以查官网,然后就可以在上面用了
        props:{
            cityArray:Array,
        }
    }
</script>
<style>
</style>

子组件Vcontent

<template>
    <div class="wrap">  
        <div class="t">
        <button @click='addCunHandler'>添加一个村庄</button>
        </div>

        <div class="mark">
            <textarea rows="10" cols="100" class="editor" v-model = 'markValue'></textarea>
            <div class="show" v-html = 'markedValue'></div>
        </div>
    </div>
</template>
<script>
    // npm install marked --save,别人写好的markdown工具,直接解析你的markdown语法
    import Marked from 'marked'
    export default {
        name:'Vcontent', 
        data(){             
            return {
                markValue:''
            }
        },
        methods:{
            // 子组件向父组件传值,第二步就是触发自定义事件
            addCunHandler(){
                // 通过$emit触发自定义事件
                // 参数1:自定义事件的名字
                // 参数2:数据
                this.$emit('addCunHandler','北海北');
            }
        },
        computed:{
            markedValue(){
                return Marked(this.markValue)
            }
        }
    }
</script>
<style scoped>
    .t {
        width: 300px;
        height: 100px;
    }
    .mark{
        width:1210px;
        height: 600px;
        margin: 0 auto;
    }
    .editor,.show{
        float: left;
        width: 603px;
        height: 600px;
        border: 1px solid #666;
    }
</style>

子组件Vheader

<template>
    <header class="header"> 
        <div class="nav">
            <div class="logo">
                <img :src="imgSrc" />
            </div>
            <div class="info">
                <button>注册</button>
                <button>登陆</button>
            </div>
        </div>
    </header>
</template>
<script>
    import imgSrc from '../assets/logo.png'
    export default {
        name:'Vheader',    
        data(){             
            return {
                imgSrc:imgSrc
            }
        },
    }
</script>
<style scoped>
    .header{
        width: 100%;
        height: 40px;
        background-color: #fff;
        box-shadow: 0 2px 4px 0 #c9c9c9; /* box-shadow是框边的阴影,更有立体感*/ 
    }
    .header .nav{
        width: 980px;
        height: 40px;
        margin: 0 auto;
        /*transparent透明*/
        background-color: transparent;
    }
    .nav .logo{
        width: 100px;
        height: 40px;
        float: left;
    }
    .logo img{
        width: 40px;
        height: 40px;
    }
    .nav .info{
        float: right;
        width: 200px;
        height: 40px;
    }
    .info button{
        width: 80px;
        height: 40px;
        float: left;
    }
</style>

 

posted @ 2019-06-28 14:50  load晴天  阅读(10120)  评论(0编辑  收藏  举报