分类 Javascript 下的文章

Vue 实现父子组件双向绑定最正确的做法

最近在学习 vue ,遇到了父子组件数据绑定的问题。Vue 官方文档有这样一段话:

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

但这并不是说父页面就不能跟子组件双向通讯,不过就是麻烦了一点。在 Google 了诸多之后,尝试了网络上一些破碎零星的代码(什么计算属性,侦听器等)之后,终于找到了最佳的做法:prop.sync

完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Prop 双向绑定的实现</title>
    <script src="dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h1>父组件数据</h1>
    <table>
        <tr>
            <th>姓名</th>
            <th>年龄</th>
        </tr>
        <tr>
            <td>{{ name }} <input type="text" v-model="name" /></td>
            <td>{{ age }} <input type="number" v-model.number="age" /></td>
        </tr>
    </table>
    <!--
      v-bind:my-name
      v-on:update:my-name="my-name = $event"
    参考文档
      https://cn.vuejs.org/v2/guide/components-custom-events.html
    -->
    <user-table
      v-bind:my-name.sync="name"
      v-bind:my-age="age"
      v-on:change-age="age = $event"
    ></user-table>
</div>
<template id="userTable">
    <div>
        <h2>子组件数据</h2>
        <table>
            <tr>
                <th>姓名</th>
                <th>年龄</th>
            </tr>
            <tr>
                <td>{{ myName }} <input type="text" :value="myName" @input="updateName" /></td>
                <td>{{ myAge }} <input type="number" :value="myAge" @input="updateAge" /></td>
            </tr>
        </table>
    </div>
</template>
<style>
table, td, th {
    border-collapse: collapse;
    border-spacing: 0
}
table {
    margin: 20px;
}
td, th {
    border: 1px solid #bcbcbc;
    padding: 5px 10px
}
th {
    background: #42b983;
    font-weight: 400;
    color: #fff;
    cursor: pointer
}
</style>
<script>
var UserTable = {
  props: {
    myName: String,
    myAge: Number
  },
  template: '#userTable',
  watch: {
    myName: function (val) {
      console.log('child-component watch fater-component name:' + val)
    },
    myAge: function (val) {
      console.log('child-component watch father-component age:' + val)
    }
  },
  methods: {
    updateName (evt) {
      console.log(evt)
      console.log('_name value:' + this.myName)
      console.log('evt.target.value:' + evt.target.value)
      this.$emit('update:myName', evt.target.value)
      console.log('child-component myName:' + this.myName)
    },
    updateAge (evt) {
      console.log(evt)
      console.log('_name value:' + this.myAge)
      console.log('evt.target.value:' + evt.target.value)
      // 自定义 change-age 事件
      this.$emit('change-age', Number(evt.target.value))
      console.log('child-component myAge:' + this.myAge)
    }
  }
}
new Vue({
  el: '#app',
  data: {
    name: '张三',
    age: 20
  },
  components: {
    'user-table': UserTable
  },
  mounted() {
    const vm = this
    setInterval(() => { console.log('name', this.name, 'age', this.age); }, 3000);
  }
})
</script>
</body>
</html>

使用 Event-Emit 方式实现的示例(请随意在输入框中输入数据,观察数据文本变化):

https://raoyc.com/learning_vue/example/cp_2.html

- 阅读剩余部分 -

MarkdocViewer

最近闲来无聊造了个文档阅读的东西,就一个单页,欢迎使用。

传送门:https://github.com/ycrao/markdoc-viewer

MarkdocViewer : reading markdown documentation from open git repository (just in one page) !

MarkdocViewer :从公开的 git 仓库阅读 markdown 文档 (就一个页面)!

参数配置

MarkdocViewer默认配置如下:

    this.defaults = {
            'base_url': 'https://raw.githubusercontent.com/',  //git 公共仓库 raw 基地址
            'base_dir': '',  //文档所在子目录,默认为空
            'repo_name': 'yascmf/docs',  //文档仓库名,默认为作者的 YASCMF 文档库
            'branch_name': 'master',  //文档所在分支,默认为master
            'index_file': 'index.md',  //目录索引文件,默认为index.md
            'home_file': 'readme.md',  //目录默认主页文件,默认为readme.md
            'sider_id': 'sider-menu',  //导航目录所在div的id名
            'content_id': 'content',  //markdown正文所在div的id名
        };

以上某些配置,可以通过传入查询串,予以重载新配置:

https://raoyc.com/markdoc-viewer?dir=&repo=yascmf/docs&branch=master&index=index.md&home=readme.md

其中,dir 查询串对应 base_dirrepo 对应 repo_name 配置,后面依次类推。请保证,查询串值与仓库文档实际结构目录一致。

- 阅读剩余部分 -

json对象的遍历

在写内容管理框架时,需要实现根据当前路由 url 自动对导航栏特定项目予以高亮。由于,原有 cmf 是使用 json 结合 laytpl 模版引擎生成导航栏。

这个过程中需要使用到 json 对象遍历,下面简单学习下对如何对json数据遍历。
这里主要使用到 for ( var d in data ) 语句,对于复杂结构的 json 数据比较好用。


- 阅读剩余部分 -

JSONPath的使用

某些情况下,我们需要查询json对象特定属性值下的结果,通过JSONPath可以很方便我们查询。

关于 JsonPath 的介绍,http://goessner.net/articles/JsonPath/JsonPath 对于 JSON 来说相当于 XPATH 对于 XML 。这是一个简单的从文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Java, PythonPHP 等。

这里我要演示的是 javascript 实现版本,使用的 jsonpath 类库来自 GitHubjQuery-JSONPath ,注意该类库依赖于 jQuery

- 阅读剩余部分 -

Javascript获取当前URL相关参数

演示代码:

var search = window.location.search; //获取url中"?"符后的字串
var hash = window.location.hash; //获取url中"#"锚点符
        
        var parser = document.createElement('a');
        //var parser = {};
        parser.href = "http://example.com:3000/pathname/?search=test#hash";
        parser.protocol; // => "http:"
        parser.hostname; // => "example.com"
        parser.port;     // => "3000"
        parser.pathname; // => "/pathname/"
        parser.search;   // => "?search=test"
        parser.hash;     // => "#hash"
        parser.host;     // => "example.com:3000"
        /*
        hash     从井号 (#) 开始的 URL(锚)
        host     主机名和当前 URL 的端口号
        hostname     当前 URL 的主机名
        href     完整的 URL
        pathname     当前 URL 的路径部分
        port     当前 URL 的端口号
        protocol     当前 URL 的协议
        search     从问号 (?) 开始的 URL(查询部分)
        */
    console.log(search);
    console.log(hash);
 

- 阅读剩余部分 -