Vue 组件细节问题

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <table>
                <tbody>
                    <tr><td>1</td></tr>
                    <tr><td>2</td></tr>
                    <tr><td>3</td></tr>
                    <tr><td>4</td></tr>
                </tbody>
            </table>
        </div>
    </body>
</html>

上面是一个 table,我们需要复用 tr 标签。
然后就写一个组件来复用。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <table>
                <tbody>
                    <row></row>
                    <row></row>
                    <row></row>
                    <row></row>
                </tbody>
            </table>
        </div>
        
        <script>
            Vue.component('row', {
                template: '<tr><td>This is a row.</td></tr>'
            })
        </script>
    </body>
</html>

然而实际上跑起来居然没有任何效果。

这是因为我们没有托管

这个区域,所以无法识别我们自己创建的组件。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <table>
                <tbody>
                    <row></row>
                    <row></row>
                    <row></row>
                    <row></row>
                </tbody>
            </table>
        </div>
        
        <script>
            Vue.component('row', {
                template: '<tr><td>This is a row.</td></tr>'
            })
            
            var vm = new Vue({
                el: '#app'
            })
        </script>
    </body>
</html>

终于有效果了,然而仔细看看HTML页面的代码,就会发现这个效果不是我们想要的。

<div id="app">
<tr><td>This is a row.</td></tr>
<tr><td>This is a row.</td></tr>
<tr><td>This is a row.</td></tr>
<tr><td>This is a row.</td></tr>
<table><tbody></tbody></table>
</div>

这个不符合 HTML Table 标签的规范。

<div id="app">
<table>
    <tbody>
        <tr is="row"></tr>
        <tr is="row"></tr>
        <tr is="row"></tr>
        <tr is="row"></tr>
    </tbody>
</table>
</div>

通过 is 属性就可以解决这个问题了。

子组件里面,data 不能是对象,只能是属性。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <table>
                <tbody>
                    <tr is="row"></tr>
                    <tr is="row"></tr>
                    <tr is="row"></tr>
                    <tr is="row"></tr>
                </tbody>
            </table>
        </div>
        
        <script>
            Vue.component('row', {
                data: function() {
                    return {
                        content: 'This is a row.',
                    }
                },
                template: '<tr><td>{{content}}</td></tr>'
            })
            
            var vm = new Vue({
                el: '#app'
            })
        </script>
    </body>
</html>

每一个子组件都会被多次调用,所以应该有自己的空间,不会被干扰,所以data 必须为函数。

通过 ref 引用来操作DOM,虽然Vue 不建议直接操作DOM,但是有些时候不得不操作DOM。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <div ref="hello" @click="handleClick">Hello World</div>
        </div>
        
        <script>
            var vm = new Vue({
                el: '#app',
                methods: {
                    handleClick: function() {
                        console.log(this.$refs.hello)
                        console.log(this.$refs.hello.innerHTML)
                    }
                }
            })
        </script>
    </body>
</html>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="./vue.v2.6.10.dev.js"></script>
    </head>
    <body>
        <div id="app">
            <counter ref="one" @change="handleChange"></counter>
            <counter ref="two" @change="handleChange"></counter>
            <div>{{total}}</div>
        </div>
        
        <script>
            Vue.component('counter', {
                template: '<div @click="handleClick">{{number}}</div>',
                data: function() {
                    return {
                        number: 0,
                    }
                },
                methods:{
                    handleClick: function() {
                        this.number++
                        this.$emit('change')
                    },
                }
            })
            var vm = new Vue({
                el: '#app',
                data: {
                    total: 0,
                },
                methods: {
                    handleChange: function() {
                        console.log(this.$refs.one)
                        console.log(this.$refs.one.number)
                        console.log(this.$refs.two)
                        console.log(this.$refs.two.number)
                        this.total = this.$refs.one.number + this.$refs.two.number
                    }
                }
            })
        </script>
    </body>
</html>