zoukankan      html  css  js  c++  java
  • vue小案例--简易评论区

    一、小案例(评论区)

    1、流程

    (1)分析静态页面。(vue项目创建参考https://www.cnblogs.com/l-y-h/p/11241503.html)
    (2)拆分静态页面,变成一个个组件。
    (3)对组件编码,生成动态页面。

    2、静态页面

    参考来源:https://www.bilibili.com/video/av49099807/?p=22&t=1223

    【举例:】
    <!DOCTYPE html>
    <html>
    
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width,initial-scale=1.0">
            <!--此处如果bootstrap选用 4.3.1的版本,样式会无效(没去研究)-->
            <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
            <script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/js/bootstrap.js"></script>
            <title>vue_demo</title>
        </head>
    
        <body>
            <div id="app">
                <div>
                    <!--头部-->
                    <header class="site-header jumbotron">
                        <div class="container">
                            <div class="row">
                                <div class="col-xs-12">
                                    <h1>欢迎来到吐槽大厅</h1>
                                </div>
                            </div>
                        </div>
                    </header>
    
                    <!--主体部分-->
                    <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
                    <div class="container">
                        <div class="col-md-4">
                            <form action="form-horizontal">
                                <div class="form-group">
                                    <label>用户名</label>
                                    <input type="text" class="form-control" placeholder="用户名">
                                </div>
                                <div class="form-group">
                                    <label>吐槽内容</label>
                                    <textarea type="text" class="form-control" placeholder="吐槽内容"></textarea>
                                </div>
                                <div class="form-group">
                                    <div class="col-sm-offset-2 col-sm-10">
                                        <button type="button" class="btn btn-default pull-right">提交</button>
                                    </div>
                                </div>
                            </form>
                        </div>
                        <!--md4 for Add end    -->
    
                        <div class="col-md-8">
                            <h3 class="reply">吐槽回复:</h3>
                            <h2>暂无吐槽,点击左侧添加吐槽吧!</h2>
                            <ul class="list-group">
                                <li class="list-group-item">
                                    <div class="handle col-sm-offset-2 col-sm-10">
                                        <a class="pull-right">删除</a>
                                    </div>
                                    <p class="user"><span>Tom</span><span>说:</span></p>
                                </li>
                                <li class="list-group-item">
                                    <div class="handle col-sm-offset-2 col-sm-10">
                                        <a class="pull-right">删除</a>
                                    </div>
                                    <p class="user"><span>Tom</span><span>说:</span></p>
                                </li>
                            </ul>
                        </div>
                        <!--md8 for List end -->
                    </div>
                </div>
            </div>
            <!--app -->
        </body>
    
    </html>

    页面截图:

    3、拆分静态页面,

    拆分静态页面,使其变成一个个静态组件。

    Step1:是一个大的组件(App),里面包含各种组件。

    Step2:页面内容可以拆分成 提交吐槽组件(Comment),吐槽回复组件(Comments)。

    Step3:吐槽回复组件里面 可以对 每一条吐槽进行拆分,即每个吐槽为一个组件(Item)。

    文件结构如下:

    【主要文件与文件夹:】
    index.html    主页面,所有组件操作均为其服务,在此处引入css、js文件
    main.js       vue入口文件,从此处启动vue
    App.vue       App.vue组件,项目的入口组件
    components      里面保存各个小组件
    
    
    【index.html】
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <!--所有组件都是为index.html服务的,所以在此处引入css、js文件-->
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
        <title>vuedemo</title>
      </head>
      <body>
        <noscript>
          <strong>We're sorry but vuedemo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
    
    【main.js】
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    
    【App.vue】
    <template>
        <div>
            <!--头部-->
            <header class="site-header jumbotron">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12">
                            <h1>欢迎来到吐槽大厅</h1>
                        </div>
                    </div>
                </div>
            </header>
    
            <!--主体部分-->
            <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
            <div class="container">
                <!--使用各组件-->
                <Comment></Comment>
                <Comments></Comments>
            </div>
        </div>
        <!--App -->
    </template>
    
    <script>
        // 引入各组件
        import Comment from './components/Comment.vue'
        import Comments from './components/Comments.vue'
    
        export default {
            name: 'app',
            // 注册各组件
            components: {
                Comment,
                Comments
            }
        }
    </script>
    
    <style>
    </style>
    
    
    【Comment.vue】
    <template>
        <div class="col-md-4">
            <form action="form-horizontal">
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control" placeholder="用户名">
                </div>
                <div class="form-group">
                    <label>吐槽内容</label>
                    <textarea type="text" class="form-control" placeholder="吐槽内容"></textarea>
                </div>
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <button type="button" class="btn btn-default pull-right">提交</button>
                    </div>
                </div>
            </form>
        </div>
        <!--Comment -->
    </template>
    
    <script>
        export default{
            name: 'comment'
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Comments.vue】
    <template>
        <div class="col-md-8">
            <h3 class="reply">吐槽回复:</h3>
            <h2>暂无吐槽,点击左侧添加吐槽吧!</h2>
            <ul class="list-group">
                <Item></Item>
            </ul>
        </div>
        <!--md8 for List end -->
    </template>
    
    <script>
        import Item from './Item.vue'
        
        export default{
            name: 'comments',
            components: {
                Item
            }
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Item.vue】
    <template>
        <!--注意,需要使用div包裹,否则会报错-->
        <div>
            <li class="list-group-item">
                <div class="handle col-sm-offset-2 col-sm-10">
                    <a class="pull-right">删除</a>
                </div>
                <p class="user"><span>Tom</span><span>说:</span></p>
            </li>
            <li class="list-group-item">
                <div class="handle col-sm-offset-2 col-sm-10">
                    <a class="pull-right">删除</a>
                </div>
                <p class="user"><span>Tom</span><span>说:</span></p>
            </li>
        </div>
    </template>
    
    <script>
        export default{
            name: 'item'
        }
    </script>
    
    <style>
    
    </style>

    拆分后效果与原静态页面一致。

    4、组件间值的传递(组件间通信)

      静态页面上吐槽区的内容不会是写好的,是动态生成的,那么如何生成,就涉及到组件间的值的传递。通过props 来声明属性,使用data来传递数据(属性值),使用 v-bind 绑定属性。

    【对上面代码进行修改】
    App.vue              获取数据,将数据往吐槽区(Comments.vue)传
    Comments.vue         接收App.vue传来的数据,将每条数据往Item.vue传
    Item.vue             接收Comments.vue传来的数据并显示
    
    要是一眼看不出来,可以下载个Bcompare软件,自行比较一下代码间的区别。
    
    【App.vue】
    <template>
        <div>
            <!--头部-->
            <header class="site-header jumbotron">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12">
                            <h1>欢迎来到吐槽大厅</h1>
                        </div>
                    </div>
                </div>
            </header>
    
            <!--主体部分-->
            <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
            <div class="container">
                <!--使用各组件-->
                <Comment></Comment>
                       <!--需使用v-bind绑定属性-->
                <Comments :contents="contents"></Comments>
            </div>
        </div>
        <!--App -->
    </template>
    
    <script>
        // 引入各组件
        import Comment from './components/Comment.vue'
        import Comments from './components/Comments.vue'
    
        export default {
            name: 'app',
            // 注册各组件
            components: {
                Comment,
                Comments
            },
            
            // 传递数据
            data(){
                return {
                    contents:[
                        {name: 'tom', content: '妈妈,我想吃烤山药'},
                        {name: 'jarry', content: '吃,吃大块的'},
                        {name: 'jarry', content: '两块够不'},
                        {name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
                    ]
                }
            }
        }
    </script>
    
    <style>
    </style>
    
    
    【Comments.vue】
    <template>
        <div class="col-md-8">
            <h3 class="reply">吐槽回复:</h3>
            <ul class="list-group">
                <Item v-for="(content, index) in contents" :key="index" :content="content"></Item>
            </ul>
        </div>
        <!--md8 for List end -->
    </template>
    
    <script>
        import Item from './Item.vue'
        
        export default{
            name: 'comments',
            // 声明接收属性,此属性可以在该组件中使用
            props: ['contents'],  // 只指定属性名
            
            // 注册组件
            components: {
                Item
            }
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Item.vue】
    <template>
        <!--注意,需要使用div包裹,否则会报错-->
        <div>
            <li class="list-group-item">
                <div class="handle col-sm-offset-2 col-sm-10">
                    <a class="pull-right">删除</a>
                </div>
                <p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
            </li>
        </div>
    </template>
    
    <script>
        export default{
            name: 'item',
            props: {
                // 指定属性名以及属性值的类型
                content : Object
             }
        }
    </script>
    
    <style>
    
    </style>

    效果如下图:

    5、动态交互--添加

      实现添加吐槽操作。

      使用v-on 绑定事件,使用v-model 实现数据的双向绑定,方法也可以使用 v-bind 绑定 并进行组件通信。

    【对上面代码进行修改】
    App.vue            定义增加吐槽的方法,并作为属性传递给Comment.vue组件
    Comment.vue        接收属性,并定义添加数据的事件
    
    【App.vue】
    <template>
        <div>
            <!--头部-->
            <header class="site-header jumbotron">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12">
                            <h1>欢迎来到吐槽大厅</h1>
                        </div>
                    </div>
                </div>
            </header>
    
            <!--主体部分-->
            <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
            <div class="container">
                <!--使用各组件-->
                <Comment :addComment="addComment"></Comment>
                <!--需使用v-bind绑定属性-->
                <Comments :contents="contents"></Comments>
            </div>
        </div>
        <!--App -->
    </template>
    
    <script>
        // 引入各组件
        import Comment from './components/Comment.vue'
        import Comments from './components/Comments.vue'
    
        export default {
            name: 'app',
            // 注册各组件
            components: {
                Comment,
                Comments
            },
            
            // 传递数据
            data(){
                return {
                    contents:[
                        {name: 'tom', content: '妈妈,我想吃烤山药'},
                        {name: 'jarry', content: '吃,吃大块的'},
                        {name: 'jarry', content: '两块够不'},
                        {name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
                    ]
                }
            },
            
            // 操作数据的方法
            methods: {
                addComment(comment){
                    // 在数组头部插入数据
                    this.contents.unshift(comment);
                }
            }
        }
    </script>
    
    <style>
    </style>
    
    
    【Comment.vue】
    <template>
        <div class="col-md-4">
            <form action="form-horizontal">
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control" placeholder="用户名" v-model="name">
                </div>
                <div class="form-group">
                    <label>吐槽内容</label>
                    <textarea type="text" class="form-control" placeholder="吐槽内容" v-model="content"></textarea>
                </div>
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <button type="button" class="btn btn-default pull-right" @click="add">提交</button>
                    </div>
                </div>
            </form>
        </div>
        <!--Comment -->
    </template>
    
    <script>
        export default{
            name: 'comment',
            data(){
                return {
                    name : '',
                    content : ''
                }
            },
            props:{
                // 定义属性类型、属性值类型、必须性
                addComment: { 
                    type: Function,
                    required: true
                }
            },
            methods: {
                add(){
                    // step1:进行合法性检验
                    const name = this.name.trim();
                    const content = this.content.trim();
                    if(!name || !content){
                        alert("输入内容不能为空");
                        return;
                    }
                    
                    // step2:将name,content封装成一个comment(吐槽)对象
                    const comment = {name, content};
                    
                    console.log(comment);
                    // step3: 将comment 加入到 comments(吐槽区)
                    this.addComment(comment);
                    
                    // step4:清空输入框
                    this.name = '';
                    this.content = '';
                }
            }
        }
    </script>
    
    <style>
    
    </style>

    效果:

    6、动态交互--删除

      进行删除操作。

      类似于添加操作。

    【对上面文件进行修改】
    App.vue             定义删除数据的方法,并将其作为属性传递给Comments.vue
    Comments.vue        作为一个中间的组件,传递index以及删除方法
    Item.vue            接收Comments.vue传递的属性,并定义删除事件
    
    
    【App.vue】
    <template>
        <div>
            <!--头部-->
            <header class="site-header jumbotron">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12">
                            <h1>欢迎来到吐槽大厅</h1>
                        </div>
                    </div>
                </div>
            </header>
    
            <!--主体部分-->
            <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
            <div class="container">
                <!--使用各组件-->
                <Comment :addComment="addComment"></Comment>
                <!--需使用v-bind绑定属性-->
                <Comments :contents="contents" :deleteComment="deleteComment"></Comments>
            </div>
        </div>
        <!--App -->
    </template>
    
    <script>
        // 引入各组件
        import Comment from './components/Comment.vue'
        import Comments from './components/Comments.vue'
    
        export default {
            name: 'app',
            // 注册各组件
            components: {
                Comment,
                Comments
            },
            
            // 传递数据
            data(){
                return {
                    contents:[
                        {name: 'tom', content: '妈妈,我想吃烤山药'},
                        {name: 'jarry', content: '吃,吃大块的'},
                        {name: 'jarry', content: '两块够不'},
                        {name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
                    ]
                }
            },
            
            // 操作数据的方法
            methods: {
                addComment(comment){
                    // 在数组头部插入数据
                    this.contents.unshift(comment);
                },
                deleteComment(index){
                    // 删除指定下标的数据
                    this.contents.splice(index, 1);
                }
            }
        }
    </script>
    
    <style>
    </style>
    
    
    【Comments.vue】
    <template>
        <div class="col-md-8">
            <h3 class="reply">吐槽回复:</h3>
            <h3 v-show="contents.length === 0">暂无吐槽,点击左侧提交吐槽!!!</h3>
            <ul class="list-group">
                <Item v-for="(content, index) in contents" :key="index" :content="content" :deleteComment="deleteComment" :index="index"></Item>
            </ul>
        </div>
        <!--md8 for List end -->
    </template>
    
    <script>
        import Item from './Item.vue'
    
        export default {
            name: 'comments',
            // 声明接收属性,此属性可以在该组件中使用
            props: ['contents', 'deleteComment'], // 只指定属性名
    
            // 注册组件
            components: {
                Item
            }
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Item.vue】
    <template>
        <!--注意,需要使用div包裹,否则会报错-->
        <div>
            <li class="list-group-item">
                <div class="handle col-sm-offset-2 col-sm-10">
                    <a class="pull-right" @click="deleteItem">删除</a>
                </div>
                <p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
            </li>
        </div>
    </template>
    
    <script>
        export default{
            name: 'item',
            props: {
                // 指定属性名以及属性值的类型
                content : Object,
                deleteComment : Function,
                index : Number 
             },
             methods: {
                 deleteItem() {
                     const {content, deleteComment, index} = this;
                     // 使用  反引号 + ${}, ES6模板字符串
                     if(window.confirm(`确定删除${content.name}的评论吗?`)){
                         deleteComment(index);
                     }
                 }
             }
        }
    </script>
    
    <style>
    
    </style>

    运行结果:

    7、完整代码

    (1)项目结构以及修改的文件

    (2)代码

    【index.html】
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <!--所有组件都是为index.html服务的,所以在此处引入css、js文件-->
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
        <title>vuedemo</title>
      </head>
      <body>
        <noscript>
          <strong>We're sorry but vuedemo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
    
    【main.js】
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    
    【App.vue】
    <template>
        <div>
            <!--头部-->
            <header class="site-header jumbotron">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12">
                            <h1>欢迎来到吐槽大厅</h1>
                        </div>
                    </div>
                </div>
            </header>
    
            <!--主体部分-->
            <!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
            <div class="container">
                <!--使用各组件-->
                <Comment :addComment="addComment"></Comment>
                <!--需使用v-bind绑定属性-->
                <Comments :contents="contents" :deleteComment="deleteComment"></Comments>
            </div>
        </div>
        <!--App -->
    </template>
    
    <script>
        // 引入各组件
        import Comment from './components/Comment.vue'
        import Comments from './components/Comments.vue'
    
        export default {
            name: 'app',
            // 注册各组件
            components: {
                Comment,
                Comments
            },
            
            // 传递数据
            data(){
                return {
                    contents:[
                        {name: 'tom', content: '妈妈,我想吃烤山药'},
                        {name: 'jarry', content: '吃,吃大块的'},
                        {name: 'jarry', content: '两块够不'},
                        {name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
                    ]
                }
            },
            
            // 操作数据的方法
            methods: {
                addComment(comment){
                    // 在数组头部插入数据
                    this.contents.unshift(comment);
                },
                deleteComment(index){
                    // 删除指定下标的数据
                    this.contents.splice(index, 1);
                }
            }
        }
    </script>
    
    <style>
    </style>
    
    
    【Comment.vue】
    <template>
        <div class="col-md-4">
            <form action="form-horizontal">
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control" placeholder="用户名" v-model="name">
                </div>
                <div class="form-group">
                    <label>吐槽内容</label>
                    <textarea type="text" class="form-control" placeholder="吐槽内容" v-model="content"></textarea>
                </div>
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <button type="button" class="btn btn-default pull-right" @click="add">提交</button>
                    </div>
                </div>
            </form>
        </div>
        <!--Comment -->
    </template>
    
    <script>
        export default{
            name: 'comment',
            data(){
                return {
                    name : '',
                    content : ''
                }
            },
            props:{
                // 定义属性类型、属性值类型、必须性
                addComment: { 
                    type: Function,
                    required: true
                }
            },
            methods: {
                add(){
                    // step1:进行合法性检验
                    const name = this.name.trim();
                    const content = this.content.trim();
                    if(!name || !content){
                        alert("输入内容不能为空");
                        return;
                    }
                    
                    // step2:将name,content封装成一个comment(吐槽)对象
                    const comment = {name, content};
                    
                    console.log(comment);
                    // step3: 将comment 加入到 comments(吐槽区)
                    this.addComment(comment);
                    
                    // step4:清空输入框
                    this.name = '';
                    this.content = '';
                }
            }
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Comments.vue】
    <template>
        <div class="col-md-8">
            <h3 class="reply">吐槽回复:</h3>
            <h3 v-show="contents.length === 0">暂无吐槽,点击左侧提交吐槽!!!</h3>
            <ul class="list-group">
                <Item v-for="(content, index) in contents" :key="index" :content="content" :deleteComment="deleteComment" :index="index"></Item>
            </ul>
        </div>
        <!--md8 for List end -->
    </template>
    
    <script>
        import Item from './Item.vue'
    
        export default {
            name: 'comments',
            // 声明接收属性,此属性可以在该组件中使用
            props: ['contents', 'deleteComment'], // 只指定属性名
    
            // 注册组件
            components: {
                Item
            }
        }
    </script>
    
    <style>
    
    </style>
    
    
    【Item.vue】
    <template>
        <!--注意,需要使用div包裹,否则会报错-->
        <div>
            <li class="list-group-item">
                <div class="handle col-sm-offset-2 col-sm-10">
                    <a class="pull-right" @click="deleteItem">删除</a>
                </div>
                <p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
            </li>
        </div>
    </template>
    
    <script>
        export default{
            name: 'item',
            props: {
                // 指定属性名以及属性值的类型
                content : Object,
                deleteComment : Function,
                index : Number 
             },
             methods: {
                 deleteItem() {
                     const {content, deleteComment, index} = this;
                     // 使用  反引号 + ${}, ES6模板字符串
                     if(window.confirm(`确定删除${content.name}的评论吗?`)){
                         deleteComment(index);
                     }
                 }
             }
        }
    </script>
    
    <style>
    
    </style>

    运行结果此处不再重复截图,与上述截图相同。

  • 相关阅读:
    Android Apk获取包名和Activity名称
    SoupUI接口测试学习分享
    Android 手机自动化测试工具有哪几种?
    SVN和CVS的区别
    名词
    本地解析地址步骤
    python3.6.1+selenium3.0环境安装问题及解决方法
    简述企业信息化与企业架构关系
    企业架构实践的线下公开课学习感悟
    golang 12.9 go mod 实践
  • 原文地址:https://www.cnblogs.com/l-y-h/p/11647918.html
Copyright © 2011-2022 走看看