An efficient way is the other answer using the element api and vue.js. The element api returns JSON and VUE uses javascript templating to output the markup. The same can be done in jQuery using a template framework like Mustache. However if you need something less in-depth with jQuery here is a simple way to accomplish it.
First in your settings go to Routes and create a new route to the template file which will generate your posts.
For the more button you could use a data attribute to capture the current page along with how many you would like to load at a time.
<button id="more-button" data-page="0" data-batch="3">More</button>
In jQuery listen for the button click and run your query to the template.
$("#more-button").on('click', function () {
var btn = $(this),
page = btn.data('page'),
batch = btn.data('batch'),
offset = page * batch,
newPage = page + 1;
loadPosts(offset, batch);
// set the buttons page attribute to the new page it is on.
btn.data('page',newPage);
});
function loadPosts (offset, limit) {
$.get('/ajax/posts', { offset:offset, limit:limit }, function (data) {
var postOutput = $('#post-output');
postOutput.html(data);
});
}
In your template you will need to capture the offset & limit params.
{% set offset = craft.request.getParam('offset') %}
{% set limit = craft.request.getParam('limit') %}
{% set items = craft.entries.section('projects').limit(limit).offset(offset) %}
In this example we are retrieving the next set and appending them to the rest of the posts.
Again for a more efficient experience try using element api & javascript templating.